This release includes 10 security fixes for security teams reviewing exposed deployments.
Topics
+13 more
Affected surfaces
Summary
AI summaryBroad release touches Other Changes, Bug Fixes, Dependency Updates, and fix.
Full changelog
Version: 3.9.0
Highlights
Native Permission Engine
A brand-new permission engine now governs access across the entire application, replacing ad-hoc role checks with a centralized, fail-closed authorization layer. The engine was rolled out domain by domain — Tickets, Comments, Users, Clients, Settings, Sprints, Wiki, Ideas, Goals, Blueprints, Canvas, Calendar, Timesheets, Files, Reports, and the Projects service — closing numerous cross-user IDORs and information-disclosure oracles along the way. (#3461, #3469, #3471, #3472, #3473)
Unified Blueprints Domain
The 16 separate canvas variant domains have been consolidated into a single unified Blueprints domain with native Laravel controllers, dramatically reducing duplicated code while preserving every canvas type. Legacy Canvas and Strategy code now lives as thin deprecated adapters over Blueprints. (#3483, #3486)
JSON-RPC API
A new JSON-RPC API layer replaces the legacy REST/JSON controllers, with migrated endpoints for Tickets, Users, Ideas, Calendar, Notifications, Reactions, Sessions, Submenu, and more, plus a plugin gate attribute and capability-discovery endpoint for extensions. (#3457)
New Features
- Mobile Push Notifications - Mobile devices can now register Expo/FCM push tokens against access tokens and receive ticket and unread-count notifications via a new dispatcher (#3398, #3401, #3457)
- Logic Model Board - Added a Logic Model canvas board with WorkStructure orchestration (#3455)
- WorkStructure Meta-Model - New WorkStructure meta-model infrastructure underpinning structured work hierarchies (#3454)
- Task Collaborators - Completed multi-collaborator support for tasks, ensuring collaborators always receive ticket notifications and appear with full metadata across list and widget views (#1099)
- "Not Assigned" Milestone Filter - Added a "Not assigned" option to the tickets milestone filter (#3452)
- Stage Row Hover Spotlight - Hovering a stageflow row now spotlights it by dimming non-hovered stages (#3481)
- Blade Component Tiers - Introduced tiered Blade components with a central HTMX event convention (#3441)
Bug Fixes
- Postgres Compatibility - Fixed write limits, sequences, pdo_pgsql handling, and JS escaping for PostgreSQL deployments (#3447)
- Auth & Dashboard 500s - Hardened authentication and the dashboard against server errors and offline hangs (#3448)
- Marketplace 500s - Stopped marketplace errors by coercing API data into typed model properties (#3446)
- Ticket Editor Role on Save - Enforced the editor role when saving and correctly honored milestone project changes (#3445)
- Ticket Modal Milestone Crash - Fixed a crash in the ticket modal when handling milestone-type items
- Milestone & Wiki Dialogs - Restored data binding in the milestone and wiki dialogs (#3444)
- Save Notes from All Notes Grid - Notes saved from the All Notes grid now land in a default notebook (#3451)
- Weekly Timesheet Grid - Blank cells are now skipped when saving the weekly grid (#3449)
- Comment Edit/Reply Box - The edit and reply box now opens above the replies thread (#3450)
- Comments Template Variable - Stopped the comments template from shadowing the controller's comments array (#3459)
- Client Discussion Count - Fixed an inaccurate discussion count on the client detail page (#3426)
- Client Detail 500 - Resolved an undefined constant crash on the client detail page
- Value Proposition Canvas - Fixed an undefined variable on the Value Proposition Canvas (#3402)
- Logic Model Status Filter - Left-aligned the status filter dropdown menu on the Logic Model board (#3484)
- Ticket List Variables - Guarded undefined groupBy/newField variables in ticket list views
- Helm Session Expiration Units - Corrected session expiration units in the Helm chart (#3487, #3378)
- Mobile Responsiveness - Responsive stabilization sweep for phones and tablets (#3442)
Improvements
- Dashboard Performance - Eliminated full-page repaints and cross-widget loading-indicator churn and sped up hot paths via session locking, query dedupe, and improved event patterns (#3439, #3443)
- Thin Controllers - Modernized every domain controller from
run()toget()/post()thin-controller patterns across the entire codebase - Typed Exceptions - Added a typed exception hierarchy and JSON-RPC response types, with RPC-only service methods throwing typed exceptions on denial
- Consolidated Permission Migrations - Merged the 14 permission-engine migrations into a single install migration (#3506)
- Static Analysis - Raised PHPStan static analysis to level 1 (#3440)
Security
- projectIdParam Validation - Project ID parameters are now validated as real positive integers and fail closed when a mandatory ID can't be resolved (#3507, #3509)
- Projects Service Hardening - Gated the Projects god-service with recursion-safe manager+ management checks (#3505)
- Calendar IDOR Fixes - Gated the Calendar domain and closed cross-user IDORs (#3504)
- Reports Surface Reduction - Gated the Reports domain and de-exposed the system/telemetry RPC surface (#3501)
- Files IDOR Fixes - Gated the Files domain and closed RPC IDORs (#3492)
- Timesheets Authorization - Gated the Timesheets domain with own-time vs manage separation and matrix edit (#3490)
- Goals & Canvas Authorization - Gated the Goals and consolidated Canvas domains and closed by-id IDORs (#3483, #3485, #3486)
- Comment Authorization - Scoped comment authorization to the host entity's real project and closed the comment-existence oracle in reaction methods
- Tags IDOR - Closed the Tags
getTagsIDOR and removed dead REST controllers - CSRF Hardening - Excluded install routes from CSRF verification while forms are tokenized
- Comprehensive Remediation - Comprehensive remediation across seven vulnerability families
Dependency Updates
- Bumped shell-quote from 1.8.2 to 1.8.4 to clear a critical advisory (#3502)
- Bumped icalendar and dotlottie-wc, removed Dependabot config (#3438)
- Bumped webpack-cli from 5.1.4 to 7.0.3 (#3413)
- Bumped katex from 0.16.21 to 0.17.0 (#3410)
- Bumped fullcalendar from 6.1.17 to 6.1.20 (#3417)
- Bumped @fullcalendar/luxon3 from 6.1.17 to 6.1.20 (#3409)
- Switched html2canvas and jsPDF to npm-managed dependencies (#3482)
What's Changed
Other Changes
- Fix case sensitivity in secondary color setting by @Delvar in https://github.com/Leantime/leantime/pull/3348
- Fix syntax for Referrer-Policy header assignment by @Delvar in https://github.com/Leantime/leantime/pull/3347
- build(deps): bump brace-expansion by @dependabot[bot] in https://github.com/Leantime/leantime/pull/3340
- Update ko-KR.ini — complete Korean translation by @madrobotnet in https://github.com/Leantime/leantime/pull/3326
- build(deps-dev): bump yauzl from 3.2.0 to 3.2.1 by @dependabot[bot] in https://github.com/Leantime/leantime/pull/3320
- make MarketplacePlugin model properties nullable for PHP 8.x by @shaunchokshi in https://github.com/Leantime/leantime/pull/3356
- Add collaborator support to task assignment and UI (list + kanban) by @juarezsousa-ctrl in https://github.com/Leantime/leantime/pull/3337
- fix: Postgres compat + plugin install null-safety (bundles 4 issues) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3359
- fix: moveTicket, KPI linking, backlog filter on Postgres, tiptap list rendering by @marcelfolaron in https://github.com/Leantime/leantime/pull/3360
- fix: wiki sidebar width, dark-mode editor dropdowns, emoji ESC propagation by @marcelfolaron in https://github.com/Leantime/leantime/pull/3361
- Backend API surface for Leantime Mobile (TestFlight) by @gloriafolaron in https://github.com/Leantime/leantime/pull/3395
- Fix three bugs: isset on null param, redundant limit(1), malformed URL by @YoussefMansour9 in https://github.com/Leantime/leantime/pull/3393
- Implement Arabic language by @Mohd-PH in https://github.com/Leantime/leantime/pull/3370
- fix: add error403.blade.php to resolve crash on permission-gated pages by @Copilot in https://github.com/Leantime/leantime/pull/3365
- fix: Resend Invite button silently no-ops due to isset(null) check by @mojotaker in https://github.com/Leantime/leantime/pull/3392
- Fix favorites star spinning indefinitely after click on Project Hub by @Copilot in https://github.com/Leantime/leantime/pull/3364
- refactor: migrate all .tpl.php/.sub.php/.inc.php templates to Blade by @marcelfolaron in https://github.com/Leantime/leantime/pull/3362
- fix: 6 high-impact bugs — PDO crash, commenter role, Wiki Postgres, Ideas canvasId, Kanban scroll by @marcelfolaron in https://github.com/Leantime/leantime/pull/3397
- fix(calendar): tolerate MySQL zero-date sentinel in getCalendar by @gloriafolaron in https://github.com/Leantime/leantime/pull/3396
- Security: comprehensive remediation across 7 vulnerability families by @marcelfolaron in https://github.com/Leantime/leantime/pull/3399
- Modernize all controllers from run() to get()/post() by @marcelfolaron in https://github.com/Leantime/leantime/pull/3408
- fix: Value Proposition Canvas 500 (Undefined variable $currentCanvas) (#3402) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3422
- Refactor: thin controllers / fat services across all non-canvas domains by @marcelfolaron in https://github.com/Leantime/leantime/pull/3420
- refactor: consolidate canvas domains into a unified Blueprints domain (YAML-driven) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3421
- feat(api): JSON-RPC migration foundation + Tickets pilot by @marcelfolaron in https://github.com/Leantime/leantime/pull/3424
- feat(api): JSON-RPC migration batch 2 — Submenu, Sessions, Reactions, Notifications by @marcelfolaron in https://github.com/Leantime/leantime/pull/3425
- Fix 500 on client detail page: undefined constant generalComment by @Roark1138 in https://github.com/Leantime/leantime/pull/3423
- fix(clients): show accurate discussion count on client detail page by @marcelfolaron in https://github.com/Leantime/leantime/pull/3428
- feat(api): JSON-RPC migration batch 3 — Calendar (+ delete dead Ideation) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3426
- feat(api): JSON-RPC migration — Ideas (with project-access authorization) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3427
- feat(api): JSON-RPC migration — Users JSON endpoints by @marcelfolaron in https://github.com/Leantime/leantime/pull/3429
- Retire the legacy Api REST controllers (binary/upload → domains, Projects sort → JSON-RPC, delete dead Tags/Timer) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3430
- refactor(blueprints): native Laravel controllers, drop the dispatch bridge by @marcelfolaron in https://github.com/Leantime/leantime/pull/3432
- feat(core): typed exception hierarchy + JSON-RPC response types by @marcelfolaron in https://github.com/Leantime/leantime/pull/3431
- fix(tickets): guard undefined $groupBy/$newField in list views by @marcelfolaron in https://github.com/Leantime/leantime/pull/3433
- cleanup: remove dead $x = $x; Blade self-assign artifacts by @marcelfolaron in https://github.com/Leantime/leantime/pull/3434
- refactor: merge Strategy domain into Blueprints by @marcelfolaron in https://github.com/Leantime/leantime/pull/3435
- feature: RPC-only service methods throw typed exceptions on denial by @marcelfolaron in https://github.com/Leantime/leantime/pull/3436
- Fix #1099 by @duongynhi000005-oss in https://github.com/Leantime/leantime/pull/3405
- feat(tickets): finish collaborators feature — notifications, persistence & hardening (#1099) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3437
- build(deps): bump @fullcalendar/luxon3 from 6.1.17 to 6.1.20 by @dependabot[bot] in https://github.com/Leantime/leantime/pull/3409
- build(deps): bump fullcalendar from 6.1.17 to 6.1.20 by @dependabot[bot] in https://github.com/Leantime/leantime/pull/3417
- build(deps): bump katex from 0.16.21 to 0.17.0 by @dependabot[bot] in https://github.com/Leantime/leantime/pull/3410
- build(deps-dev): bump webpack-cli from 5.1.4 to 7.0.3 by @dependabot[bot] in https://github.com/Leantime/leantime/pull/3413
- chore(deps): bump icalendar + dotlottie-wc, remove Dependabot by @marcelfolaron in https://github.com/Leantime/leantime/pull/3438
- perf: speed up dashboard & hot paths (session locking, query dedupe, event patterns) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3439
- ci(phpstan): raise static analysis to level 1 by @marcelfolaron in https://github.com/Leantime/leantime/pull/3440
- fix(mobile): responsive stabilization sweep for phones & tablets by @marcelfolaron in https://github.com/Leantime/leantime/pull/3442
- perf(dashboard): stop full-page repaints & cross-widget loading-indicator churn by @marcelfolaron in https://github.com/Leantime/leantime/pull/3443
- feat(components): Blade component tiers + central HTMX event convention by @marcelfolaron in https://github.com/Leantime/leantime/pull/3441
- fix: restore data binding in milestone & wiki dialogs by @marcelfolaron in https://github.com/Leantime/leantime/pull/3444
- fix: repair #3441 regressions blocking acceptance (app.js bundle syntax + stale install step) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3453
- fix(tickets): enforce editor role on save + honor milestone project change by @marcelfolaron in https://github.com/Leantime/leantime/pull/3445
- fix(plugins): stop marketplace 500s by coercing API data to typed model props by @marcelfolaron in https://github.com/Leantime/leantime/pull/3446
- fix(db): PostgreSQL compatibility (write limits, sequences, pdo_pgsql, JS escaping) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3447
- fix(ldap): return a normal auth error instead of a 500 on bad credentials by @marcelfolaron in https://github.com/Leantime/leantime/pull/3448
- fix(comments): open the edit/reply box above the replies thread by @marcelfolaron in https://github.com/Leantime/leantime/pull/3450
- feat(tickets): add "Not assigned" milestone filter option (#3252) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3452
- feat(core): WorkStructure meta-model infrastructure by @marcelfolaron in https://github.com/Leantime/leantime/pull/3454
- fix(timesheets): skip blank cells when saving the weekly grid by @marcelfolaron in https://github.com/Leantime/leantime/pull/3449
- fix(wiki): save notes from the All Notes grid into a default notebook by @marcelfolaron in https://github.com/Leantime/leantime/pull/3451
- feat(notifications): mobile push device tokens (Expo + FCM) + getUnreadCount RPC (#3398) by @gloriafolaron in https://github.com/Leantime/leantime/pull/3401
- feat(logicmodelcanvas): Logic Model board + WorkStructure orchestration by @marcelfolaron in https://github.com/Leantime/leantime/pull/3455
- feat(notifications): mobile push tokens on access_tokens + FCM/Expo dispatcher by @gloriafolaron in https://github.com/Leantime/leantime/pull/3457
- fix(comments): stop shadowing controller $comments array in Discussion template by @gloriafolaron in https://github.com/Leantime/leantime/pull/3459
- feat(core): native permission engine foundation (Phase 0) + console addCommand fix by @marcelfolaron in https://github.com/Leantime/leantime/pull/3461
- feat(permissions): enforce Tickets + Comments via the engine — full @api coverage by @marcelfolaron in https://github.com/Leantime/leantime/pull/3469
- feat(permissions): roll the engine across the Users domain (company-scope) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3471
- feat(permissions): roll the engine across the Clients domain (company-scope) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3472
- feat(permissions): roll the engine across the Setting domain (company + project scopes) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3473
- feat(permissions): roll the engine across the Sprints domain (first content domain) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3474
- feat(api): plugin gate attribute + capability discovery endpoint by @gloriafolaron in https://github.com/Leantime/leantime/pull/3460
- fix(tickets): ticket modal crashes on milestone type by @gloriafolaron in https://github.com/Leantime/leantime/pull/3468
- security(comments): scope comment authz to the host entity's real project by @marcelfolaron in https://github.com/Leantime/leantime/pull/3476
- security(ideas): gate Ideas domain on the native permission engine by @marcelfolaron in https://github.com/Leantime/leantime/pull/3478
- security(wiki+ideas): gate the Wiki and Ideas domains on the native permission engine by @marcelfolaron in https://github.com/Leantime/leantime/pull/3479
- security(blueprints): gate the consolidated canvas domain + close by-id IDORs by @marcelfolaron in https://github.com/Leantime/leantime/pull/3483
- security(goalcanvas): gate the Goals domain + close by-id IDORs by @marcelfolaron in https://github.com/Leantime/leantime/pull/3485
- security(canvas): gate the legacy Canvas-base controllers (Logicmodelcanvas) + Api\Canvas by @marcelfolaron in https://github.com/Leantime/leantime/pull/3486
- fix(helm): correct session expiration units in Helm chart (fixes #3378) by @dashitongzhi in https://github.com/Leantime/leantime/pull/3487
- fix(logicmodelcanvas): left-align status filter dropdown menu by @gloriafolaron in https://github.com/Leantime/leantime/pull/3484
- feat(stageflow): spotlight non-hovered stages on row hover by @gloriafolaron in https://github.com/Leantime/leantime/pull/3481
- feat(libs): npm-manage html2canvas + jsPDF by @gloriafolaron in https://github.com/Leantime/leantime/pull/3482
- security(timesheets): gate the Timesheets domain (own-time vs manage) + matrix edit by @marcelfolaron in https://github.com/Leantime/leantime/pull/3490
- security(files): gate the Files domain + close RPC IDORs by @marcelfolaron in https://github.com/Leantime/leantime/pull/3492
- chore(logicmodelcanvas): drop unused snapshot mount div by @gloriafolaron in https://github.com/Leantime/leantime/pull/3491
- security(reports): gate the Reports domain + de-expose system/telemetry RPC surface by @marcelfolaron in https://github.com/Leantime/leantime/pull/3501
- fix(deps): bump shell-quote 1.8.2 → 1.8.4 (clear critical advisory) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3502
- security(calendar): gate the Calendar domain + close cross-user IDORs by @marcelfolaron in https://github.com/Leantime/leantime/pull/3504
- security(projects): gate the Projects god-service (recursion-safe, manager+ management) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3505
- refactor(install): consolidate the 14 permission-engine migrations into one by @marcelfolaron in https://github.com/Leantime/leantime/pull/3506
- security(permissions): fail closed when a mandatory projectIdParam can't be resolved by @marcelfolaron in https://github.com/Leantime/leantime/pull/3507
- ci(release): one-dispatch release pipeline (version bump, AI changelog, PR gate, auto-publish) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3508
- security(permissions): validate projectIdParam is a real positive integer by @marcelfolaron in https://github.com/Leantime/leantime/pull/3509
- ci(release): swap changelog generation from GitHub Models to the Claude API by @marcelfolaron in https://github.com/Leantime/leantime/pull/3510
- Release v3.9.0 by @marcelfolaron in https://github.com/Leantime/leantime/pull/3511
- ci(release): set up PHP before make package (fixes v3.9.0 release build) by @marcelfolaron in https://github.com/Leantime/leantime/pull/3512
New Contributors
- @Delvar made their first contribution in https://github.com/Leantime/leantime/pull/3348
- @madrobotnet made their first contribution in https://github.com/Leantime/leantime/pull/3326
- @shaunchokshi made their first contribution in https://github.com/Leantime/leantime/pull/3356
- @juarezsousa-ctrl made their first contribution in https://github.com/Leantime/leantime/pull/3337
- @YoussefMansour9 made their first contribution in https://github.com/Leantime/leantime/pull/3393
- @Mohd-PH made their first contribution in https://github.com/Leantime/leantime/pull/3370
- @Copilot made their first contribution in https://github.com/Leantime/leantime/pull/3365
- @mojotaker made their first contribution in https://github.com/Leantime/leantime/pull/3392
- @Roark1138 made their first contribution in https://github.com/Leantime/leantime/pull/3423
- @duongynhi000005-oss made their first contribution in https://github.com/Leantime/leantime/pull/3405
- @dashitongzhi made their first contribution in https://github.com/Leantime/leantime/pull/3487
Full Changelog: https://github.com/Leantime/leantime/compare/v3.7.3...v3.9.0
Breaking Changes
- Unified Blueprints domain replaces 16 separate canvas variant domains; legacy Canvas and Strategy code is now deprecated adapters over the new domain.
- JSON‑RPC API layer replaces legacy REST/JSON controllers for Tickets, Users, Ideas, Calendar, Notifications, Reactions, Sessions, Submenu and more.
Security Fixes
- projectIdParam validation now enforces real positive integers and fails closed when resolution fails (CVE not listed).
- Projects service hardening adds recursion‑safe manager+ checks.
- Calendar domain gated to close cross‑user IDORs.
- Reports surface reduced by gating Reports domain and de‑exposing system/telemetry RPC surface.
- Files domain gated and RPC IDORs closed.
- Timesheets authorization separated into own‑time vs manage matrix edit.
- Goals and consolidated Canvas domains gated, closing by‑id IDORs.
- Comment authorization scoped to host entity's real project, closing comment‑existence oracle.
- Tags `getTags` endpoint IDOR fixed and dead REST controllers removed.
- CSRF hardening excludes install routes from verification while forms remain tokenized.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About leantime
Leantime is a goals focused project management system for non-project managers. Building with ADHD, Autism, and dyslexia in mind.
Beta — feedback welcome: [email protected]