Wekan
Open source kanban board application built with Meteor
Alternative to: trello
v10.82
2026-08-11Binaries 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.49.0 | verified | 7c74941ff043f26a… |
| amd64 | Node.js | nodejs.org | v24.19.0 | verified | 14b342e71204f811… |
| arm64 | FerretDB | wekan/FerretDB | v1.49.0 | verified | 092132531555a39e… |
| arm64 | Node.js | nodejs.org | v24.19.0 | verified | 01443c1e1a29e531… |
| armhf | FerretDB | wekan/FerretDB | v1.49.0 | verified | 144404fb9793dc8e… |
| armhf | Node.js | wekan/node-patches | v24.19.0 | verified | b55350f3071b765a… |
| armv6 | FerretDB | wekan/FerretDB | v1.49.0 | verified | 7c27b2c15448709a… |
| armv6 | Node.js | wekan/node-patches | v24.19.0 | verified | 128ded0cda638c1f… |
| armv7 | FerretDB | wekan/FerretDB | v1.49.0 | verified | 144404fb9793dc8e… |
| armv7 | Node.js | wekan/node-patches | v24.19.0 | verified | 8dbe0a9aa8550ad5… |
| i386 | FerretDB | wekan/FerretDB | v1.49.0 | verified | 1f70cb1687411b2a… |
| i386 | Node.js | wekan/node-patches | v24.19.0 | verified | 3b0b3bbfe27daf58… |
| mac-arm64 | FerretDB | wekan/FerretDB | v1.49.0 | verified | 576364db59dfce3b… |
| mac-arm64 | Node.js | nodejs.org | v24.19.0 | verified | 3f1cf157479c1480… |
| mac-x64 | FerretDB | wekan/FerretDB | v1.49.0 | verified | 37d70cd90aad6d38… |
| mac-x64 | Node.js | nodejs.org | v24.19.0 | verified | d35e95230f46f6f0… |
| ppc64le | FerretDB | wekan/FerretDB | v1.49.0 | verified | 7c61d4853d5163ad… |
| ppc64le | Node.js | nodejs.org | v24.19.0 | verified | c510c6ce12f07010… |
| riscv64 | FerretDB | wekan/FerretDB | v1.49.0 | verified | bd4912da70f5e6c1… |
| riscv64 | Node.js | unofficial-builds.nodejs.org | v24.19.0 | verified | cd1f14af28121480… |
| s390x | FerretDB | wekan/FerretDB | v1.49.0 | verified | 62900110fc3e8165… |
| s390x | Node.js | nodejs.org | v24.19.0 | verified | a4792e65962ffa0a… |
| win-arm64 | FerretDB | wekan/FerretDB | v1.49.0 | verified | 792166623e774b0a… |
| win-arm64 | Node.js | nodejs.org | v24.19.0 | verified | 8502f4a50b458d4c… |
| win64 | FerretDB | wekan/FerretDB | v1.49.0 | verified | f42c50aa84095a96… |
| win64 | Node.js | nodejs.org | v24.19.0 | verified | 57f71ab3652e797d… |
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.
v10.82 2026-08-11 WeKan ® release
In short: a CRITICAL SECURITY ISSUE, WhereBleed: eight Admin Panel
handlers took a query selector from the client and checked only its type, so a
$where in one made the database run the caller’s JavaScript - a repeatable
denial of service, reachable by a per-tenant admin. The detector for it was
already in the codebase and wired into one publication; the eight siblings never
called it, and now share the one copy. Then the snap, where two permanent
markers meant an instance that had failed on an older revision never retried on
the fixed one, so the MongoDB 4.2 reader added for it never ran.
Notifications grew an unbounded array inside the user document that SQLite
was rewriting on every addition, which is the slow login and the pinned CPU.
Clicking an open card closes it again, and a focused Admin Panel checkbox is
no longer drawn as a diamond. It also adds the first new feature in this
release: checklists and card feature groups fold away, on the opened card
and on the minicard, asked for since 2018. Below that: a typed two-digit year
refused rather than stored as the year 26, the Helm chart index listing only
charts that can be installed, and a way to remove the Templates containers made
for accounts that never used them. And two developer-facing fixes: the
database-conformance stage no longer opens a debug port nothing in it uses - one
taken by an unrelated FerretDB made every backend report a database problem that
was not one - and two more snap give-up paths that deleted the directory their
own stage filter names. The binaries below are v10.81’s: nothing here rebuilds
them.
| Platform | Binary | From | Version | SHA256 |
|---|---|---|---|---|
| amd64 | Node.js | nodejs.org | v24.19.0 | 14b342e71204f811bde6153be8e04b62aef63c236fef92b55f9c83154b409647 |
| amd64 | FerretDB | wekan/FerretDB | v1.48.0 | 2737687fd29a8a761cd960e45f300b68cf7b4a87d50c4cc5280bcbd42b6aa163 |
| arm64 | Node.js | nodejs.org | v24.19.0 | 01443c1e1a29e531ccad5a46fefa6df490d2189c49f7955904aecdbb0fe86fdc |
| arm64 | FerretDB | wekan/FerretDB | v1.48.0 | 5ae705dd49515a4ecd4e295c3b9aa4f3b454fad78613ec60fb99316bd7c34e3f |
| loong64 | Node.js | unofficial-builds.nodejs.org | v24.19.0 | c24f224726f2d785bd18a1fd09f5e6d1fecf0269928451a60c5da9eac8e92e68 |
| loong64 | FerretDB | wekan/FerretDB | v1.48.0 | 06ec86263455a7b598d22a87df0e044ea73ab5a3b72e96ad12ebed03c1374ac2 |
| mac-arm64 | Node.js | nodejs.org | v24.19.0 | 3f1cf157479c1480352083105e13faf9d008ede98e7e157746b6df940d197b94 |
| mac-arm64 | FerretDB | wekan/FerretDB | v1.48.0 | 9b15f4c10e473cd0a2c4feb4cb43e18042bd60c7035ec66cab3cfbe13edaabab |
| mac-x64 | Node.js | nodejs.org | v24.19.0 | d35e95230f46f6f0751df497c56622c6735e05d5e1fb1630996a005b9d328fe4 |
| mac-x64 | FerretDB | wekan/FerretDB | v1.48.0 | 4e188246dfa33bccef4cdd86701bc498b037cb3e91f579ff0dccb93aa0ef03ad |
| ppc64le | Node.js | nodejs.org | v24.19.0 | c510c6ce12f07010f771e6edb22a3fe23f4f2e6f40b1ffd4941aed0646a0d8b3 |
| ppc64le | FerretDB | wekan/FerretDB | v1.48.0 | 0400cd6dfc3d10d987a0fe80d75baa86c03c19170770fa2e602c92d558c3cfa6 |
| riscv64 | Node.js | unofficial-builds.nodejs.org | v24.19.0 | cd1f14af2812148002f58b58a5f9af512a50e3b8e8c148e0db44019dcb68edfd |
| riscv64 | FerretDB | wekan/FerretDB | v1.48.0 | d37c35af988670b9ed182b8c5966c06a06362f6c6ace6aebd93ccdfa32c9a26b |
| s390x | Node.js | nodejs.org | v24.19.0 | a4792e65962ffa0af42627aacf1122a60c3c88dbf4e4184f06820d66f9da8ba4 |
| s390x | FerretDB | wekan/FerretDB | v1.48.0 | 6c7d61fbb8c79b2e8733be8f71910f710e8c5cd25208c451bdc513c8313b0340 |
| win64 | Node.js | nodejs.org | v24.19.0 | 57f71ab3652e797d84acddc79c81cc9ff1c6ddb2a1974cdb83f00fee9bff4c73 |
| win64 | FerretDB | wekan/FerretDB | v1.48.0 | ea57e1bcd153b51d2065ab01515b21ec05d8f615444c15603ab8158b8a661dd2 |
This release fixes the following CRITICAL SECURITY ISSUE of WhereBleed:
The Admin Panel’s People, Org, Team and Translation panes - what a query from the client is allowed to be.
WhereBleed: eight Admin Panel handlers ran the caller's selector unchecked. Thanks to TungNGo02 and xet7.
WhereBleed -
GHSA-phm4-4v26-j2vq,
Moderate, CWE-943, CVSS 5.8. The people, org, team and translation publications
and their companion count/page methods take a query selector from the client and
validate only its TYPE - check(query, Match.OneOf(Object, null)) - which is
not validation, because a MongoDB selector is executable data. $where makes
the database run the caller’s JavaScript once per document scanned, so
Meteor.subscribe('team', { $where: 'while(true){}' }, 25, 0) pins a database
worker for as long as the caller likes, repeatably: denial of service for every
tenant on the instance from one narrowly-scoped account.
The reporter demonstrated both halves on v10.81 against a real MongoDB 7:
$where: 'sleep(2000) || true' made the subscription take 2.03s and return the
document, $where: 'false' returned nothing in 0.00s - the caller deciding, in
JavaScript, which documents come back.
It needs an authenticated admin session, so no board member or visitor can reach
it. It matters at this severity because the people and org surfaces are open to
a per-tenant Global Admin, a role meant to be confined to one Organization,
and those two wrap the caller’s selector as { $and: [query, restriction] }
rather than stripping execution operators out of it - so merging the tenant
restriction never removed the $where, and a role scoped to one tenant reached
instance-wide impact.
What makes this one particular is that the defence was already in the
codebase. classifySelector and hasWhere were written for exactly this
class, are unit-tested, and were wired into the card-window publication. Eight
sibling handlers taking the identical shape of selector simply never called
them. So the fix adds no new detection logic: that publication’s own helper
moves unchanged into a shared module and all nine call sites use the one copy -
a second copy would be the same bug set up to happen again.
Each handler refuses with the “match nothing” selector the card window already
uses in production, { _id: { $in: [] } }, so a refused request returns an
empty result instead of throwing at an admin mid-page. Ordinary behaviour is
untouched: none of the searches, filters, regexes,
$or/$and/$in/$elemMatch or date ranges those panes send carries an
execution operator.
FerretDB, WeKan’s default database, rejects $where itself, so this degrades to
a rejected query there; the supported MongoDB path is where it was reproduced.
MongoDB 7 also happens to reject $where inside the aggregation pipeline the
count methods use - but that is an engine accident for one operator on one call
path, so those methods are guarded like the rest rather than left to it.
and adds the following new feature:
Cards - folding away what you are not reading.
Checklists and card feature groups collapse, on the opened card and on the minicard. Thanks to czinkos, MikeRatcliffe, JannetGen and xet7.
Asked for in 2018: “It would be great to have collapsable checklists on cards”, and again this week - “Long checklists can make a card pretty cluttered, so being able to collapse them and expand only when needed would keep the board much cleaner.”
WeKan had something adjacent and it was not this. A checklist carries
hideAllChecklistItems, reachable through a toggle switch inside the checklist
actions popup - but that is a field ON THE CHECKLIST, so flipping it changes
what everyone on the board sees, and it is an edit to the card rather than a
view preference. It is untouched; it has its own uses.
Collapsing is per-user, which WeKan already says twice in its own models for lists and swimlanes, so this follows them: one map in the user profile keyed by card. A feature group uses its own section name, an individual checklist uses a key of its own - which is why folding a checklist on the opened card folds it on the minicard too.
The control is a caret on the title rather than another entry in a menu, since the point is to fold at a glance while reading the card. It carries aria-expanded and answers Enter and Space. For the sixteen feature groups on the opened card it is done once, with a delegated handler and CSS: they all open with a title but only three wrap what follows in a content element, so folding hides every sibling after the title, which works whatever a section puts there.
A checklist’s progress bar stays visible when folded - it is the summary of what was folded away - and the fold survives reopening the card.
and fixes the following bugs:
The snap, upgrading from an old MongoDB - and why a fixed version changed nothing.
A new snap revision is a new chance, so the MongoDB 4.2 reader actually gets to run. Thanks to Philippe-Bentegeac, JDeepix, imlit and xet7.
Reported against 10.81: “I still have the exact same issue, MongoDB cannot start. The web interface is still unreachable, and I do not see the messages you added in the last commits.” The messages were missing because the code that prints them never ran.
Two markers in $SNAP_COMMON stop the snap doing work, and both were PERMANENT.
.mongodb-data-too-old is written when no reader in the snap could open the
data, after which mongod is not started at all; .mongod-start-failures is a
counter that, past three, stops the migration being re-run so a migration/mongod
restart loop cannot form. Both are right, and both record a conclusion about
what THAT snap could do.
An instance that had already failed on 10.79 or 10.80 - before mongod 4.2 was bundled - carried a marker saying “no reader can open this” and a counter far past three. So 10.81 never started mongod, never attempted the migration, and printed nothing new. Upgrading to the version with the fix changed nothing, which is exactly what their log shows: the database-selection line, then “Waiting for MongoDB replica set primary…” forever.
Each marker now records the revision that wrote it, and one from a different revision is ignored and cleared - a marker with no revision recorded at all is stale by definition, which is precisely what the affected instances carry. Within one revision nothing changes, so the loop protection still holds; and not knowing the revision is never taken as evidence that it changed.
Notifications - and the database write behind a slow login.
The notification tray is capped, so SQLite is not rewriting an ever-growing array. Thanks to Nissulya and xet7.
An instance reports FerretDB at 737% CPU, logins over a minute, boards not
appearing, and logs full of database is locked (5) (SQLITE_BUSY). The stack
names the same write every time: addNotification.
That is an $addToSet on profile.notifications, an array inside the user
document - so adding one entry reads the whole document, scans the array and
writes the document back, at a cost proportional to the array. FerretDB on
SQLite has a single writer, so those rewrites queue and start failing, and
login, which also writes to the user document, queues behind them.
It grows without limit because the existing cleanup only removes notifications
that have been READ. A user who never clears their tray accumulates entries
forever. The same pass now also keeps the newest
NOTIFICATION_TRAY_MAX_PER_USER (default 1000) and drops the rest. It is
applied to what is left after the expiry pull, a user needing no change is not
written to at all, and it stays one write per user. This bounds the array; it
does not make SQLite a multi-writer engine, and a busy instance still wants the
PostgreSQL backend.
Cards and the Admin Panel - two things people asked for in the same thread.
Clicking an open card closes it, and a focused checkbox is not drawn as a diamond. Thanks to csonkaoszimt, Heart1010 and xet7.
Closing a card by clicking it again was not a missing feature - it was an unreachable one. The handler already ended with a branch that closed the open card, but the TITLE branch above it returned first, and a minicard’s title covers most of the minicard. So the second click almost always re-opened the card that was already open, and the toggle worked only if you managed to miss the title. The title branch now makes the same decision, and on a phone, where the card is a popup, the second click closes that.
The Problems page glitch in the screenshot is the focus ring. The Admin Panel draws its checkboxes as a square that morphs into a tick, and the tick IS a 40-degree rotation of the element - so a browser draws its focus ring around a rotated box, and a checkbox that is both checked and focused (which is what one you just clicked is) comes out as a blue diamond. The ring moves to the row that contains it, which is not rotated; keyboard focus stays visible.
Card dates - what a typed date actually becomes.
A typed two-digit year is refused instead of stored as the year 26. Thanks to xet7.
From email feedback: “If i write the expiration date with the keyboard it turns red, if i choose it with the date picker it is yellow. Can you please tell me the difference?” The colour was never the difference - the YEAR was.
<input type="date"> reports its value as YYYY-MM-DD, but a browser lets the
year sub-field be typed as two digits and reports exactly that: entering
31-12-26 gives “0026-12-31”, the year 26 AD. That is a valid Date, so nothing
refused it, and the card was saved with a due date two thousand years in the
past. Red is what an overdue date looks like. The attached screenshot shows it:
the yellow badges read “31-12-2026” and the red ones “31-12-26”.
Saving now refuses a year outside 1000-9999 and says which digits are missing. It refuses rather than silently correcting 0026 to 2026, because that would be a guess about a date other people’s reminders hang off.
Old template containers - the boards nobody asked for.
Remove the Templates containers that were made for accounts which never used them. Thanks to xet7.
From email feedback: FerretDB at 190-350% CPU on an instance with 14490 boards, of which 13404 are template containers, for 9264 accounts of which 478 have ever logged in.
Before v10.00 every new account got a “Templates” container board at signup whether or not the person ever saved a template. v10.00 made that lazy (#2339, #5850), so no new account creates one - but nothing removed the ones already made, and they are not visible enough for anybody to delete by hand. On that instance they are 13x the boards collection, and every query that touches boards carries it.
Because this deletes boards, the rule for what may go is narrow: only a container nobody ever used. A template saved into it, a list, swimlane or card, a second member, a rename, a star or a manual archive all keep it, and every board that is kept reports why. A rename is judged only against the titles the app itself used, so a container whose default name is in another language is not deleted for it. The default is a dry run showing what WOULD go; deleting takes a second, explicit request.
The snap database - which copy of the data it serves.
A FerretDB copy older than the MongoDB beside it is never served. Thanks to markusst1982 and xet7.
After upgrading from v6 the reporter saw “the state of the data from days ago”
and suspected a snap revert done four weeks earlier. They were right about the
cause, and nothing was lost.
The MongoDB to FerretDB migration copies MongoDB into SQLite once and writes
.migration-to-ferretdb-done. That copy is a snapshot; nothing keeps it in
step. Revert the snap to a revision that runs mongod and WeKan carries on
writing to MongoDB - for four weeks here - while the finished SQLite sits frozen
at the date it was made. Refresh forward again and the snap saw a marker plus a
non-empty SQLite, called that a completed migration and switched onto it. Every
board and card written during the revert was still on disk and simply not being
served.
The data was never in danger: it lives in $SNAP_COMMON, which is shared across
revisions and is not rolled back by a revert (unlike $SNAP_DATA, which is
per-revision). What was wrong was which of the two copies got served, and
nothing compared their ages.
A new check answers exactly that: mongod rewrites its WiredTiger files on
every commit, so the newest mtime among them is when MongoDB was last written
to, and later than the marker means the copy is behind. It counts data files
only - a newer mongodb.log means the snap was started, not that the database
changed - and allows a margin, because the migration stops its own temporary
source mongod moments after writing the marker. Anything it cannot tell is
reported as NOT stale, since the callers act on a yes.
Where mongod runs, the snap now stays on MongoDB, which has the newest data.
Where mongod cannot start at all - the case that forces the migration in the
first place - it migrates again from scratch rather than serve the old copy; the
migration reads with its own temporary mongod and the 4.2/3.2 readers, so it
still reaches everything written since. And wekan-control gains the second
half of a guard it already had: it refused to start an empty FerretDB while
MongoDB had data, and a full but out-of-date one looks worse, because WeKan
comes up with everything present except the last weeks.
Board and card drag - what scrolls while a card is held.
Dragging a card down scrolls the list, not the whole board. Thanks to markusst1982 and xet7.
“Upwards is no problem, the Line scrolls automaticly up, but this does not work downwards. The whole Page/Site scrolls down and not ne Line”.
The card drag auto-scrolls at the edges. Horizontally it picks the lane under
the pointer (#443); vertically it picked
nothing, and always scrolled .board-canvas - which holds the swimlanes -
rather than the .list-body under the pointer, which is overflow-y: scroll
and holds the cards. Scrolling the canvas moves the whole board.
The asymmetry is what makes it reproducible. Dragging up, the canvas is usually already at the top, so the handler did nothing and jQuery UI’s own scroll option - which acts on the placeholder’s scroll parent, the list body - scrolled the list, which is why up always worked. Dragging down, the canvas nearly always has room left, so the handler fired first and scrolled the board instead.
The list under the pointer is scrolled first now, and the board only once that list cannot go further - so a drag down a long list scrolls the list, and a drag past the end of it moves on to the board, which is what dragging a card into another swimlane needs.
The Helm chart index - which charts it lists.
List only the charts whose container images still exist. Thanks to xet7.
Backfilling the index taught this within the hour: Artifact Hub scans every entry and mailed a list of errors.
error scanning image ghcr.io/wekan/wekan:v9.62: image not found error scanning
image docker.io/bitnami/mongodb:7.0.14-debian-12-r3: image not found
That was this side’s doing. The rebuild listed every package on gh-pages, and a
chart is a POINTER TO CONTAINER IMAGES - one whose images have been deleted
installs and then fails at the pull, so listing it says the repository is broken
when the repository is fine and the images are gone. 135 of the 360 packages are
in that state, from two unrelated causes: six WeKan images were never pushed
(v8.30, v9.12, v9.14, v9.38, v9.39, v9.62 - releases whose own docker job
failed, and exactly the six Artifact Hub named), and 129 older charts vendor
the Bitnami mongodb subchart and pin tags Bitnami has since deleted. Charts
from 8.41 on vendor groundhog2k’s mongodb, which uses the official mongo image
and is unaffected.
The index now holds 225 entries: every one of the 216 that were listed before -
none dropped - plus the 9 backfilled packages whose images all resolve. The
exclusions are recorded in unindexed.txt beside the packages, not decided per
run, so a rebuild during a release cannot depend on reaching two registries, and
an image that comes back is one deleted line away from being listed again. The
.tgz files stay, so direct URLs keep working.
Two things this shook out. --check-images asks each registry with ITS OWN 401
challenge instead of a hard-coded token URL per host - the first attempt
reported every quay.io image as missing, including quay.io/wekan/wekan:latest,
which plainly exists. And an image that cannot be checked is never treated as
missing, only a definite 404, so a registry hiccup cannot silently unpublish
charts. release-charts.sh now refuses to publish a chart at all when
ghcr.io/wekan/wekan:v<version> does not exist, which is what created these six
in the first place.
and has the following developer-facing fixes:
The test run - a stage that failed for a reason that was not about WeKan.
The database-conformance run no longer opens a debug port nothing in it uses. Thanks to xet7.
Every backend of the conformance stage failed before a single query was compared: “Failed to create debug handler … listen tcp 127.0.0.1:8088: bind: address already in use”, then “FerretDB did not start on this backend” for each of them.
FerretDB opens a debug handler for metrics and profiling at 127.0.0.1:8088 by default and EXITS when that address is taken, so an unrelated FerretDB running on the machine made the whole stage report a database problem that was nothing of the sort - as it would for anyone with anything on that port.
The script already takes this seriously for the two ports it knows about: it picks a free wire port, makes both overridable, and says in its own comment that they are chosen so it can run while something else is running. The debug port was simply never passed. Nothing in the run queries it, so it is not opened at all - which is also what FerretDB’s own integration tests effectively do, choosing a random debug port rather than the default.
The snap build - the part that could end it.
Two more mongo42 give-up paths deleted the directory their stage filter names. Thanks to xet7.
The earlier fix for this covered one of the three ways the mongo42 part gives up
- the unsupported-architecture exit. The other two removed the whole staged
directory and exited 0, which leaves
stage: mongo42naming a path that is not there, and snapcraft ends the build on that rather than skipping it.
Those two are reached on amd64 and arm64, where the binary IS downloaded: OpenSSL 1.1 unavailable for the architecture, or the staged mongod 4.2 failing the check that it actually runs. Either would have ended the snap build for the two architectures that matter most, the same way it ended all four Launchpad ones. Both now clear the CONTENTS and keep the directory; an empty one still means “no 4.2 reader”, because every use is guarded on the binary rather than the directory.
Thanks to above GitHub users for their contributions and translators for their translations.