v1.1.0
Security release. Upgrading is strongly recommended for every installation.
Security
-
Fixed cross-project attachment disclosure and overwrite (object-level authorization / IDOR).
Kanboard authorizes these routes throughprojectAccessMap, which proves the caller
holds a role on theproject_idin the URL and inspects nothing aboutfile_id.
The controllers meanwhile loaded attachments withgetById($fileId), keyed on the id
alone, and only fell back to the row's owntask_id/project_idwhen the URL values
were0— so on the real routes the file's true owner was never compared to anything.Any user could therefore name a project they legitimately belong to in the path and a
foreign attachment id in the query:/b/<project the caller can access>/task/<any>/file/<file in a FOREIGN project>/previewThe ACL passed and the foreign file's bytes were previewed, streamed, opened in the
editor, or — throughFileEditController::update()— overwritten.HandlesAttachmentInteraction::assertAttachmentOwnership()now joinsfile_idto the
task and project named in the URL before any bytes are read, on all four actions
(preview,stream,edit,update). Covered bytests/Unit/AttachmentAuthorizationTest.php. -
Fixed the plugin's ACL layer being inert at runtime.
PermissionServicedefaulted toMockPermissionChecker(true)— an allow-everything
stub written for unit tests — and no controller ever injected anything else, so every
canUserReadFile()/canUserWriteFile()call returnedtruein production. The new
KanboardPermissionCheckeris backed by Kanboard's ownprojectPermissionModeland
userSessionand is installed automatically whenever the container provides them. It
fails closed: a checker that cannot reach the models it needs answers "no". -
Project viewers can no longer overwrite attachments.
canUserWriteFile()aliasedcanUserReadFile(), so read access implied write access.
Write now requiresisMember()rather thanisUserAllowed().
Added
Plugin::getCompatibleVersion()returning>=1.2.23— the release in which Kanboard
added thetemplate:project-overview:documents:dropdownhook this plugin attaches to.
Without the override, the inherited default claims compatibility with whatever core is
running and the hook fails silently on older versions.NOTICErecording the license and provenance of the bundled third-party JavaScript.tests/Integration/PackagingTest.phpandtests/bootstrap.php.
Changed
- Packaging is now an allow-list. The exclude-based rsync shipped
CLAUDE.md,
AGENTS.md,implementation_plan.md,settings.json,.phpunit.result.cacheand
154 KB ofwalkthrough.mdto end users. The archive now contains only the runtime plus
LICENSE/NOTICE/README/CHANGELOG, and the build fails if a development file
appears in it or if the archive root entry is notFileInteractionCore/. - Licensing is consistent.
LICENSEand the metadata had drifted apart — the LICENSE
file said one thing whilecomposer.jsonand the README said another. Everything now
declares MIT, matching theLICENSEfile, andtests/Integration/PackagingTest.php
fails if they ever disagree again.
Removed
Assets/js/preview-language-selector.js— a verbatim duplicate of the language-picker
handler already inpreview-controls.js. Both registered their own delegatedchange
listener, so a single language change fired twoKB.modal.replace()calls and the
modal was fetched and rebuilt twice.require_once __DIR__ . '/../../tests/stubs/BaseController.php'from
FilePreviewControllerandFileStreamController. Production classes must not
referencetests/, which the release archive excludes; the stub now loads from
tests/bootstrap.phpinstead.
Known issues
Assets/js/vendor/pptx-viewer.umd.jshas unresolved provenance — no license
banner, copyright, version or upstream identifier. SeeNOTICE. This must be closed
before the plugin is submitted to the Kanboard plugin directory or a release archive
containing it is published.