v11.65
Binaries in these bundles
Each bundle carries a Node.js, a FerretDB and the MongoDB Database Tools.
Which source has a given CPU varies from release to release - nodejs.org
builds some architectures, unofficial-builds others, and the
wekan/node-patches build the ones
neither of them does - and not every source publishes a checksum. This is
what went into this release, and which downloads were checked against a
published SHA256.
| Bundle | Binary | From | Version | Checked | SHA256 |
|---|---|---|---|---|---|
| amd64 | FerretDB | wekan/FerretDB | v1.78.0 | verified | 523a96e832e5947a… |
| amd64 | Node.js | nodejs.org | v24.21.0 | verified | fd8e59d5a511510f… |
| arm64 | FerretDB | wekan/FerretDB | v1.78.0 | verified | d8bb85c7ff49fe02… |
| arm64 | Node.js | nodejs.org | v24.21.0 | verified | 6ad1325edbdb5649… |
| armhf | FerretDB | wekan/FerretDB | v1.78.0 | verified | c4df2f4e6fe8fa9a… |
| armhf | Node.js | wekan/node-patches | v24.20.0 | verified | ace678ca4601db06… |
| armv6 | FerretDB | wekan/FerretDB | v1.78.0 | verified | eeb962ba8d7b76d7… |
| armv6 | Node.js | wekan/node-patches | v24.20.0 | verified | e01021ab2ddd42cd… |
| armv7 | FerretDB | wekan/FerretDB | v1.78.0 | verified | c4df2f4e6fe8fa9a… |
| armv7 | Node.js | wekan/node-patches | v24.20.0 | verified | a227473dc166e862… |
| i386 | FerretDB | wekan/FerretDB | v1.78.0 | verified | c855b2f74a7c8b13… |
| i386 | Node.js | wekan/node-patches | v24.20.0 | verified | a90b92e80d95c341… |
| mac-arm64 | FerretDB | wekan/FerretDB | v1.78.0 | verified | 34d45b3eee2f322f… |
| mac-arm64 | Node.js | nodejs.org | v24.21.0 | verified | 6239d4cf92d86448… |
| mac-x64 | FerretDB | wekan/FerretDB | v1.78.0 | verified | 1fd4a358aae472d9… |
| mac-x64 | Node.js | nodejs.org | v24.21.0 | verified | 0ae5a24c24bb7d01… |
| ppc64le | FerretDB | wekan/FerretDB | v1.78.0 | verified | ae5e77d7e26ff668… |
| ppc64le | Node.js | nodejs.org | v24.21.0 | verified | 1936fd64623a2f98… |
| riscv64 | FerretDB | wekan/FerretDB | v1.78.0 | verified | c52b5d9b477d8a73… |
| riscv64 | Node.js | unofficial-builds.nodejs.org | v24.21.0 | verified | 5c4e83d46cc1f8ee… |
| s390x | FerretDB | wekan/FerretDB | v1.78.0 | verified | 5f6e44510345e653… |
| s390x | Node.js | nodejs.org | v24.21.0 | verified | 2ef7e2ecbf7a6c2f… |
| win-arm64 | FerretDB | wekan/FerretDB | v1.78.0 | verified | ebd8eb6dac62319d… |
| win-arm64 | Node.js | nodejs.org | v24.21.0 | verified | 8779b1bde1d39f8d… |
| win64 | FerretDB | wekan/FerretDB | v1.78.0 | verified | 39b8bd8b95754497… |
| win64 | Node.js | nodejs.org | v24.21.0 | verified | 158f7685b44de51f… |
A row saying no checksum published is not a failed check - it is a
source that publishes nothing to check against. Those are the ones worth
fixing at the source.
v11.65 2026-09-09 WeKan ® release
In short: Four security advisories against Attachments/Avatars
(ostrio:files) are fixed: a critical path-traversal arbitrary file
write via the attachment upload namingFunction, a critical
unauthenticated DDP method that could wipe every attachment or avatar on
the instance, and two high missing-authorization bugs that let an
anonymous caller download any avatar (a missing protected callback,
and an unauthenticated legacy-avatar route). The AppImage no longer
mounts itself under a possibly-small /tmp, relocating to
WRITABLE_PATH/app instead.
This release fixes the following CRITICAL SECURITY ISSUES:
Unauthenticated Arbitrary File Write via Path Traversal in Attachment Upload namingFunction. Thanks to xet7.
Attachments overrode ostrio:files' sanitize() to an identity function
and used the client-supplied fileId verbatim as the on-disk file name
in namingFunction, so an anonymous upload with
fileId: "../../../../tmp/pwn" could write attacker-controlled content
anywhere the WeKan process can write - including overwriting bundle
modules for remote code execution. sanitize() is restored to the same
whitelist models/avatars.js already used for the same tokens (file
DISPLAY names are untouched - they go through a separate, unrelated
sanitizer in onBeforeUpload), and namingFunction now also validates
the sanitized fileId against the ObjectId shape WeKan itself generates,
regenerating a fresh one rather than trusting it. A blocked attempt is
recorded through the shared security log
(authz.upload-path/UploadPathBleed),
so Admin Panel / Problems shows it happened.
tests/attachmentAvatarSecurityAdvisories.test.cjs pins both the
restored sanitizer and the fileId validation, with the advisory's own PoC
string as a negative case.
Unauthenticated DDP Methods Allow Instance-Wide Deletion of Attachments and Avatars. Thanks to xet7.
ostrio:files registers its own _FilesCollectionRemove_<collection> DDP
method, gated only by allowClientCode and never routed through
Attachments.allow/Avatars.allow - those only gate the ordinary Mongo
.remove() call, not the library's own method. Attachments had no
onBeforeRemove at all, and Avatars' unconditionally returned true
(it existed only to clear the removed avatar's owner's
profile.avatarUrl), so any anonymous DDP connection could call either
method with selector {} and delete every attachment (database record
and physical file) or every avatar on the instance. Both now require
this.userId and check every file the selector actually matches:
attachments need the caller's board-write access on that file's card/
board, avatars need ownership of that avatar or site-admin status (the
existing admin "delete another user's avatar" flow keeps working). A
blocked attempt is recorded through a new
authz.file-remove/WipeBleed
catalog key. tests/attachmentAvatarSecurityAdvisories.test.cjs pins
both hooks and that an empty/non-matching selector is refused outright
rather than treated as nothing to check.
and fixes the following bugs:
Avatars - anonymous access to files nothing should have exposed.
Add the protected callback the download library needs to gate them. Thanks to xet7.
Unlike Attachments, Avatars never set protected, so ostrio:files' own
library-native download route - whose _checkAccess defaults to
allowing everything when protected is unset - served any avatar to any
anonymous caller, entirely bypassing WeKan's own isAuthorizedForAvatar
check. Avatars.protected now mirrors Attachments.protected: an
authenticated caller may always view an avatar; an anonymous one only
when the avatar's owner is a member of a public board. A denied
anonymous download is recorded under a new
authz.avatar-protected/PortraitBleed
catalog key.
serveLegacyAvatar Serves Legacy CollectionFS Avatars Without Any Authentication. Thanks to xet7.
Both routes in server/routes/avatarServer.js that fall back to reading
a legacy CollectionFS avatar in place streamed it to any caller who knew
its old cfs.avatars.filerecord id - one of the two
(/cfs/files/avatars) with no authentication check at all. Both now
require a signed-in caller (isLegacyAvatarAuthorized): legacy records
carry no owner/board link that could be safely checked for the
public-board exemption current avatars get, so this is a deliberately
narrower rule rather than reusing that exemption on an unverifiable
claim. The /cfs/files/avatars route's redirect fallback for
already-migrated avatars is untouched, so an anonymous public-board
viewer still sees those normally - only the legacy read-in-place path
now requires a login. A denied attempt is recorded under a new
authz.legacy-avatar/RelicAvatarBleed
catalog key.
tests/attachmentAvatarSecurityAdvisories.test.cjs pins both call sites
and the negative case that the redirect still works unauthenticated.
and fixes the following bug:
AppImage - its own mount filling up a small /tmp.
Relocate the AppImage's own mount from /tmp to WRITABLE_PATH/app. Thanks to xet7.
checkmk warned /tmp/.mount_wekan.OhaGOG ... 100% used because the
AppImage runtime's own read-only squashfs mount landed on a small /tmp
- a squashfs mount always reports itself as 100% used regardless of
size, so this was really "/tmpis too small for the AppImage", not a
leak. The runtime mounts itself under
$TMPDIR/.mount_<name>.<random>(defaulting to/tmp) beforeAppRun
ever runs, so the very first launch's mount cannot be redirected from
insideAppRun.AppRunnow re-execs itself once per launch with
TMPDIRset toWRITABLE_PATH/appwhen the caller has not already
chosen aTMPDIR, so every launch from then on mounts there instead -
and, on that same first launch, sweeps out any of WeKan's own orphaned
.mount_*ekan*directories left in/tmpby an earlier, uncleanly
killed run (checked against/proc/mounts, so a live one is never
touched). AppImage-only: no other WeKan platform mounts itself this way,
so Docker, snap, the.deband the bundle zip are untouched.
tests/appImageRuntime.test.cjspins the relocation, its
once-per-launch/explicit-TMPDIRguards, and that only orphaned mounts
are removed.
and has the following developer-tooling fixes:
Fix #3823 e2e test for the Show on Minicard -> Board Settings/Card move. Thanks to xet7.
The test still clicked the minicard's own "Show on Minicard" menu entry
(.js-show-on-minicard), which no longer exists after the Board
Settings / Card move earlier in this release: the checkbox
(.js-field-has-creator-on-minicard) and its behavior are unchanged, so
the test now opens it from Board Settings / Card, reached from the
board's cog menu, instead.
Update hardcoded SQLite version/source-id pins to 3.53.4. Thanks to xet7.
The modernc.org/sqlite bump (1.57.0 → 1.58.0, from the earlier
"ferretdb" dependabot group update) embeds a newer SQLite release
(3.53.3 → 3.53.4), which three tests pinned by exact string: TestDefaults
in internal/backends/sqlite/metadata/pool/pool_test.go
(sqlite_version()/sqlite_source_id()), and the BackendVersion checks
in internal/backends/backend_test.go and
internal/backends/sqlite/metadata/registry_test.go. The dependency bump
is the intended change; the guards are updated to match it.
Thanks to above GitHub users for their contributions and translators for
their translations.