Wekan logo

Wekan

Open source kanban board application built with Meteor

Alternative to: trello


About Versions (218)

v10.82

2026-08-11

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.

BundleBinaryFromVersionCheckedSHA256
amd64FerretDBwekan/FerretDBv1.49.0verified7c74941ff043f26a…
amd64Node.jsnodejs.orgv24.19.0verified14b342e71204f811…
arm64FerretDBwekan/FerretDBv1.49.0verified092132531555a39e…
arm64Node.jsnodejs.orgv24.19.0verified01443c1e1a29e531…
armhfFerretDBwekan/FerretDBv1.49.0verified144404fb9793dc8e…
armhfNode.jswekan/node-patchesv24.19.0verifiedb55350f3071b765a…
armv6FerretDBwekan/FerretDBv1.49.0verified7c27b2c15448709a…
armv6Node.jswekan/node-patchesv24.19.0verified128ded0cda638c1f…
armv7FerretDBwekan/FerretDBv1.49.0verified144404fb9793dc8e…
armv7Node.jswekan/node-patchesv24.19.0verified8dbe0a9aa8550ad5…
i386FerretDBwekan/FerretDBv1.49.0verified1f70cb1687411b2a…
i386Node.jswekan/node-patchesv24.19.0verified3b0b3bbfe27daf58…
mac-arm64FerretDBwekan/FerretDBv1.49.0verified576364db59dfce3b…
mac-arm64Node.jsnodejs.orgv24.19.0verified3f1cf157479c1480…
mac-x64FerretDBwekan/FerretDBv1.49.0verified37d70cd90aad6d38…
mac-x64Node.jsnodejs.orgv24.19.0verifiedd35e95230f46f6f0…
ppc64leFerretDBwekan/FerretDBv1.49.0verified7c61d4853d5163ad…
ppc64leNode.jsnodejs.orgv24.19.0verifiedc510c6ce12f07010…
riscv64FerretDBwekan/FerretDBv1.49.0verifiedbd4912da70f5e6c1…
riscv64Node.jsunofficial-builds.nodejs.orgv24.19.0verifiedcd1f14af28121480…
s390xFerretDBwekan/FerretDBv1.49.0verified62900110fc3e8165…
s390xNode.jsnodejs.orgv24.19.0verifieda4792e65962ffa0a…
win-arm64FerretDBwekan/FerretDBv1.49.0verified792166623e774b0a…
win-arm64Node.jsnodejs.orgv24.19.0verified8502f4a50b458d4c…
win64FerretDBwekan/FerretDBv1.49.0verifiedf42c50aa84095a96…
win64Node.jsnodejs.orgv24.19.0verified57f71ab3652e797d…

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.

PlatformBinaryFromVersionSHA256
amd64Node.jsnodejs.orgv24.19.014b342e71204f811bde6153be8e04b62aef63c236fef92b55f9c83154b409647
amd64FerretDBwekan/FerretDBv1.48.02737687fd29a8a761cd960e45f300b68cf7b4a87d50c4cc5280bcbd42b6aa163
arm64Node.jsnodejs.orgv24.19.001443c1e1a29e531ccad5a46fefa6df490d2189c49f7955904aecdbb0fe86fdc
arm64FerretDBwekan/FerretDBv1.48.05ae705dd49515a4ecd4e295c3b9aa4f3b454fad78613ec60fb99316bd7c34e3f
loong64Node.jsunofficial-builds.nodejs.orgv24.19.0c24f224726f2d785bd18a1fd09f5e6d1fecf0269928451a60c5da9eac8e92e68
loong64FerretDBwekan/FerretDBv1.48.006ec86263455a7b598d22a87df0e044ea73ab5a3b72e96ad12ebed03c1374ac2
mac-arm64Node.jsnodejs.orgv24.19.03f1cf157479c1480352083105e13faf9d008ede98e7e157746b6df940d197b94
mac-arm64FerretDBwekan/FerretDBv1.48.09b15f4c10e473cd0a2c4feb4cb43e18042bd60c7035ec66cab3cfbe13edaabab
mac-x64Node.jsnodejs.orgv24.19.0d35e95230f46f6f0751df497c56622c6735e05d5e1fb1630996a005b9d328fe4
mac-x64FerretDBwekan/FerretDBv1.48.04e188246dfa33bccef4cdd86701bc498b037cb3e91f579ff0dccb93aa0ef03ad
ppc64leNode.jsnodejs.orgv24.19.0c510c6ce12f07010f771e6edb22a3fe23f4f2e6f40b1ffd4941aed0646a0d8b3
ppc64leFerretDBwekan/FerretDBv1.48.00400cd6dfc3d10d987a0fe80d75baa86c03c19170770fa2e602c92d558c3cfa6
riscv64Node.jsunofficial-builds.nodejs.orgv24.19.0cd1f14af2812148002f58b58a5f9af512a50e3b8e8c148e0db44019dcb68edfd
riscv64FerretDBwekan/FerretDBv1.48.0d37c35af988670b9ed182b8c5966c06a06362f6c6ace6aebd93ccdfa32c9a26b
s390xNode.jsnodejs.orgv24.19.0a4792e65962ffa0af42627aacf1122a60c3c88dbf4e4184f06820d66f9da8ba4
s390xFerretDBwekan/FerretDBv1.48.06c7d61fbb8c79b2e8733be8f71910f710e8c5cd25208c451bdc513c8313b0340
win64Node.jsnodejs.orgv24.19.057f71ab3652e797d84acddc79c81cc9ff1c6ddb2a1974cdb83f00fee9bff4c73
win64FerretDBwekan/FerretDBv1.48.0ea57e1bcd153b51d2065ab01515b21ec05d8f615444c15603ab8158b8a661dd2

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: mongo42 naming 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.