Releases: wekan/wekan
v9.67
v9.67 2026-06-21 WeKan ® release
This release fixes the following bugs:
-
Reworked confusing and unreliable list widths,
#6409: a list now has one width instead of the old
"min width / max width / automatic" trio, and it reliably persists across reloads (the render now drives the
--list-widthCSS variable the styles actually use, so a width no longer reverts toautoafter reload).
A new board setting Personal list widths chooses the scope:- Off (default) — Shared: the width lives on the list (
lists.width), is the same for everyone on the board,
and only members with write access can change it (read-only/comment-only members no longer see the resize
handle). Shared widths are included in board export/import (the importer previously droppedlists.width;
it now preserves width, color and collapsed state, and the board's list-width scope). - On — Personal: each user keeps their own widths (profile, or localStorage when not logged in), falling back
to the shared width then the default. The per-list popup is simplified to a single width value plus an
Auto list width toggle (fit lists to content); the advanced per-list min/max pixel options were removed.
Auto-width follows the same Shared/Personal scope (per-board for everyone, or per-user) and is carried through
export/import. Documented indocs/Features/Lists/Lists.md.
- Off (default) — Shared: the width lives on the list (
-
rebuild-wekan.sh/rebuild-wekan.batmenu option 2 ("Build WeKan") now also clears the rspack dev-build caches
(_buildandnode_modules/.cache) in addition tonode_modules/.meteor/local/.build, so the next
meteor runrecompiles from scratch instead of occasionally serving stale modules after agitcheckout/merge. -
rebuild-wekan.sh/rebuild-wekan.batnow give the Meteor build tool and Node a larger heap by default
(TOOL_NODE_FLAGSandNODE_OPTIONS=--max-old-space-size=8192) for every dev-run, test and build option, so
long development sessions and test runs no longer crash with "FATAL ERROR: ... JavaScript heap out of memory".
Both honor an existing value, so you can lower it on machines with less RAM. -
Fixed editing the 2nd/3rd organization or team in Admin Panel › People always showing the FIRST one,
#6411: on/people, clicking Edit on any organization or team filled
the form with the first one's values (so you could never edit the others). The edit/settings popups are opened from
the row with data context{ org }/{ team }, but their helpers readthis.orgId/this.teamId(undefined
there) and calledgetOrg(undefined)/getTeam(undefined), whichfindOne({})resolves to the first document.
The popup helpers, the save handlers and the delete (settings) handlers now resolve the clicked row's id from the
{ org }/{ team }context. Verified against a running instance (each org/team now edits its own values). -
Fixed boards not rendering at all (blank board view) after the mongodb/bson 7.3.0 dependency bump. bson 7.x runs
const { startupSnapshot } = globalThis?.process?.getBuiltinModule('v8') ?? {}at module-load time; the optional
chaining stops before the call, so in the browser — where a partialprocesspolyfill exists but has no
getBuiltinModule— it threwTypeError: getBuiltinModule is not a functionwhile evaluating
client/components/cards/attachments.js(import { ObjectId } from 'bson'). That aborted the client bundle
bootstrap part-way throughclient/imports.js, so every feature imported after it (notifications, swimlanes,
rules, …) was never registered and the board view died withNo such template: notifications. Added a tiny browser
shim (client/lib/bsonBrowserShim.js, imported first inclient/main.js) that gives the browserprocessa no-op
getBuiltinModule, so bson takes its intended?? {}fallback. New unit tests
(client/lib/tests/bsonBrowserShim.tests.js); also hardened the #5686 Playwright spec to run against a rendering
board. (PR #6410) -
Fixed REST API returning HTTP 500 with a stack trace for an invalid request,
#5804: posting a comment without the requiredcommentparameter (or
to a board that does not exist) returned an HTTP 500 error page. The schema-validation error thrown on insert is a
circular object (SimpleSchemaValidationContext→SimpleSchema→ …), and serializing it crashed the response
writer (Converting circular structure to JSON). Now: thecommentparameter is validated and a missing/empty one
returns HTTP 400; an unknown board returns HTTP 404 (the board-access checks no longer dereference
board.membersof a non-existent board); the JSON response writer is crash-proof (falls back to a safe
{ "error": … }payload instead of throwing); and REST comment errors now use their real status code instead of
200. New unit tests inserver/lib/tests/apiResponseHelpers.tests.js. (PR #6406) -
Fixed selecting text in a checklist closing the card,
#5686: selecting the text of a checklist item and releasing the
mouse outside the card detail pane closed the card. The checklist items template stopsmousedownpropagation
(for item sorting), so the existingcardDetailsIsDraggingguard never engaged and the document-level
"click outside to close" handler closed the card. The close handler now also keeps the card open whenever a
live text selection is anchored inside the card pane (new propagation-independent guard
client/lib/cardCloseGuard.js), so a deliberate click on empty board space still closes the card. New unit
tests inclient/lib/tests/cardCloseGuard.tests.jsand a Playwright regression test in
tests/playwright/specs/34-checklist-text-selection.e2e.js. (PR #6407) -
Fixed list reordering throwing
403 Access deniedfor read-only members,
#5462: read-only / comment-only board members could still drag-reorder
lists, which fired a server write that allow/deny rejected with403 Access denied(the list then snapped back). Of
the three list jQuery-UI sortables inclient/components/swimlanes/swimlanes.js, one was not gated on
Utils.canModifyBoard(); it now is, consistent with the other two, plus a defense-in-depth guard so a logged-in
user without write access can never persist a reorder (anonymous public-board reordering via localStorage is
unaffected). The server already enforced this; the fix stops the unauthorized drag and the console error. New
Playwright regression test intests/playwright/specs/35-list-sort-permissions.e2e.js. (PR #6408)
Thanks to GitHub users Atry, mueller-ma and liferadioat for reporting.
v9.65
v9.65 2026-06-20 WeKan ® release
This release adds the following updates:
- Issue triage: closed 13 already-fixed Bug issues (with evidence), relabeled ~25 mislabeled feature requests to
Featurewith a "Feature Request:" title prefix, and prefixed ~35 environment-specific reports "Environment specific:" and gave them theBug:Environment-specificlabel. - Audited labels on all 533 open issues for correctness (type,
Feature:Area,Targets:,Severity:, etc.). - Added 23 missing GitHub labels found by auditing
docs/Loginanddocs/Featuresagainst the issue labels, matching the existing label style and colours (Feature:*=#0052cc,Targets:*=#fbca04), and applied them across open and closed issues:- Login methods (
Feature:User-accounts:*): ADFS, Azure, B2C, Google, Header-Login, Nextcloud, Oracle, Zitadel, Autologin, Accounts-Lockout, Forgot-Password. - Features:
Feature:LaTeX,Feature:Mermaid-Diagram,Feature:Emoji,Feature:Python,Feature:Cards:Cover,Feature:Cards:Location,Feature:Custom-Logo,Feature:RTL,Feature:Members,Feature:Multitenancy,Feature:Allow-private-boards-only. - Platform:
Targets:Apache.
- Login methods (
and adds the following new features:
- Threaded comment replies: card comments gain an optional
parentId; a "Reply" link links a new comment to its parent, rendered with an "in reply to" quote. Initial MVP
(single-level visual threading). - Restrict board admins from editing/deleting other users' comments:
new board settingrestrictCommentEditing(default off). When on, only a comment's author may edit/delete it;
enforced server-side via collection hooks. - Visible status of sub-tasks: each subtask now shows its current
list (prefixed with the board title when on a different board) read-only next to its title. - Drag-and-drop search results into board columns: cards in the
search-results list can be dragged onto board lists, reusing the existingcard.move(). MVP: drops append to
the end of the target list (no pixel-precise insertion index yet). - Per-user permanent dismissal of the Announcement banner: a user
can permanently close the current announcement so it does not reappear on reload/board-switch, until the admin
edits the announcement text (which makes it reappear for everyone). - Show how many times a card's due date was changed: the card detail
now displays a "due date changed N times" count (derived from existinga-dueAtactivities) for deadline
accountability. - Restrict adding board members to the same Organization or Team:
new global admin settingboardMembersFromSameOrgOrTeamOnly(default off). When on, a user can only be added to
a board if they share an Organization or Team with the inviter or an active board member; enforced server-side in
the invite/search paths. Site admins bypass. - Import Google Calendar
.icsfiles into board cards: MVP,
import-only. New dependency-free iCalendar parser (server/lib/icsImport.js) maps eachVEVENTto a card with
startAt/dueAtso events appear on Calendar/Gantt views, plus animportIcsToBoardMeteor method and a REST
endpointPOST /api/boards/:boardId/swimlanes/:swimlaneId/lists/:listId/ics(documented in the OpenAPI spec, with
animporticsexample inapi.py). Two-way Google Calendar sync is not included (see
wekan-ical-server for read-only WeKan→calendar export).
and fixes the following bugs:
- Fixed OIDC/OAuth2 "Log Out" redirecting to the identity provider home page instead of back to Wekan.
With autologin (OIDC_REDIRECTION_ENABLED=true), clicking Log Out redirected to the OAuth2 server URL
(for example the Keycloak base URLhttps://id.company.com), which shows an error page for non-admin
users. Added the new optionalOAUTH2_LOGOUT_ENDPOINTsetting: when set to the provider's
end_session_endpoint(Keycloak example/realms/<realm>/protocol/openid-connect/logout), Wekan now
performs an OIDC RP-initiated logout that ends the identity provider session and returns the user to
Wekan (ROOT_URL) viapost_logout_redirect_uri. When unset, logout behaviour is unchanged, so this
is backward compatible. For Keycloak 18+, add your WekanROOT_URLto the client's
Valid post logout redirect URIs. See docs/Login/Keycloak/Keycloak.md.
Thanks to zambalee and xet7. - Fixed due dates not correctly colour coded: future due dates
more than 48 hours away are now shaded grey (not-due) instead of amber (due-soon). Root cause was a
call todiff(theDate, now, 'days')where'days'is not a valid unit, so the threshold compared raw
milliseconds; replaced with a precise hours-based comparison in a single shared helper. - Fixed due date colour mismatch between list and card detail:
an overdue card now shows red in both the minicard/list and the opened card detail. The card-detail status
colours now use!importantso overdue red overrides the due-date yellow base (matching the minicard), and
the colour-decision logic is unified into one shared helper used by both views. - Fixed unable to view all cards by due date: removed the
limit: 100cap in thedueCardspublication so all of a user's due cards across boards are shown. - Fixed unable to scroll past the first cards in the Due Cards view on mobile:
the due-cards list now has a scoped scroll container with a viewport-relative max height. - Fixed card-detail sub-popups disappearing on mobile: assigning
a user or setting the due date on touch devices no longer closes the popup (touch events inside the popup no
longer bubble to the click-outside close handler on mobile viewports). - Fixed mobile board layout and tiny Home button: minicards now
render one per row (full width) on narrow screens and the header Home / All Boards button is a proper tap target. - Fixed enormous icons/menus/text after upgrade: clamped runaway
icon/label sizing on mobile. - Fixed oversized padding/margins and stray ➕ emoji from recent UI changes:
trimmed excessive padding/margins on mobile; remaining stray plus emojis are tracked for replacement with a
Font Awesome icon. - Fixed board-level search not including comments: in-board search
now matches text inside card comments, consistent with global search. - Fixed "create list" not available in Lists board-view mode: the
"Add list" composer now appears in Lists mode (using the board's default swimlane), not only in Swimlanes mode. - Fixed board/list/swimlane numbering breaking first-letter keyboard navigation:
the move/copy card popups no longer prefix a number to each option, so options start with their name again and
digit-named boards are readable. - Fixed missing notification and card-history entry when a new attachment is uploaded:
uploading an attachment now creates anaddAttachmentactivity, so card members and subscribers are notified
(consistent with attachment removal); previously the activity was never created because the store-strategy
upload hook was dead code. - Fixed copying a card selecting all/unnamed labels on the destination board:
Cards.copy()now applies the same unnamed-label
guard asCards.move()and persists the remapped labels onto the inserted card. - Fixed copied card losing its cover ("show as thumb"):
coverIdis now remapped to the newly copied
attachment instead of pointing at the original (now-unresolvable) attachment id. - Fixed deleting a date on a linked card not taking effect:
unsetReceived/unsetStart/unsetDue/unsetEndnow
resolve the real card id viagetRealId()(consistent with theset*methods) so they update the underlying
linked card, not the link placeholder. - Fixed comment-only members being able to archive cards from the UI: the archive action now respects
Utils.canModifyCard()like every other mutating card action (the server allow-rule already rejected the write;
this closes the client-side UX gap). - Fixed sub-task board being inaccessible until a reload: the "view subtask" navigation now guards against a
not-yet-loaded board, mirroring the sibling handler. - Fixed the "When a card is moved to Archive" rule trigger not being activatable: a CSS class-name mismatch (
js-add-arc-triggervs
js-add-arch-trigger) between the board-triggers template and its click handler is fixed, with a regression test. - Fixed "select all in list" crossing swimlanes: list select-all is n...
v9.64
v9.64 2026-06-20 WeKan ® release
This release fixes the following CRITICAL SECURITY ISSUE of ChecklistBleed:
- Fixed ChecklistBleed: any authenticated user can write checklist data into a private board they are not a member of (cross-board write via collection allow rule)
(GHSA-gv8h-5p3p-6hx7,
CWE-863 Incorrect Authorization). This is the same class as BoardBleed
(GHSA-gm7v-pc38-53jr), but for the card-attached Checklist and ChecklistItem documents that the
boardId-onlydenyCrossBoardMovefix did not cover. Checklists and checklist items are attached
to a card and carry a denormalizedboardId; they are MOVED between cards by$set-ting a new
cardId(and, for items, a newchecklistId) in a direct DDP collection update, after which the
Checklists.before.updatehook re-derivesboardIdfrom the destination card. The collection
allow rules (server/permissions/checklists.js,server/permissions/checklistItems.js)
authorized an update by checking only the document's CURRENT (source)cardId— i.e. the
attacker's own board — and never inspected the new destinationcardId/checklistId/boardId.
Because every logged-in user can create a board where they are a write-capable member, a
low-privileged user with write access to one board could create a checklist/item on their own
card and then, in a single/checklists/updateor/checklistItems/updateDDP call, set its
cardIdto a card in a private board where they are not a member (if they know the target card
id): the allow rule saw the attacker's source card, approved the write, and the before-update hook
attached the attacker-controlled document to the victim's private board. The protected
moveChecklistMeteor method correctly checks both source and destination board membership, but a
DDP client can bypass that method and update the collections directly. CVSS:3.1 Moderate
(AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N). Fixed by addingdenyCrossBoardMoveByCardand
denyCrossBoardMoveByChecklistItemhelpers inserver/lib/utils.jsand aChecklists.deny/
ChecklistItems.denyupdaterule on each collection that rejects any update whose destination
board — resolved from a newboardId,cardId, orchecklistIdin the modifier — the caller has
no write access to. Legitimate moves into boards the user belongs to and same-card edits keep
working, and the server-sidemoveChecklistmethod (which bypasses allow/deny) is unchanged.
A regression test (server/lib/tests/checklistbleed.security.tests.js) was added.
Affected Wekan v9.62 and earlier.
Thanks to DavidCarliez, xet7 and Claude.
and adds the following updates:
- Fix the Docker pre-build version guard false-failing the release.
The bundle-version guard added for the Admin-Panel-version fix assumed the WeKan app
package.jsonships as a standalone file with av-prefixed version, and made "not found"
fatal. Meteor does not ship it that way — it inlines the apppackage.jsoninto the compiled
bundle/programs/server/app/app.jsas a JSON module ({"name":"wekan","version":"v9.63.0",...}),
so the guard found no v-prefixedpackage.jsonand aborted the v9.63 Docker build. The guard now
reads the version from that inlined module (anchored on"name":"wekan", exactly what
require('/package.json')resolves to), and a detection miss is now a warning that continues
rather than a hard failure — only a confirmed version MISMATCH blocks the release, since
--build-arg VERSIONis the actual guarantee.
Thanks to xet7 and Claude.
Thanks to above GitHub users for their contributions and translators for their translations.
v9.63
v9.63 2026-06-19 WeKan ® release
This release adds the following features:
-
Fix the wekan.fi install page version never updating from a stale value.
Therelease-all.ymlwebsite job ran every release but the install page's
version stayed frozen at v9.57:releases/release-website.shupdated it with a
sed anchored on>v$OLD</span>, which silently no-op'd once the published
page's value no longer matched theold_versionpassed for a release. Anchor
on the stable<span class="version-number">instead and re-normalize whatever
version is there to the new one, with an assert so a miss fails loudly. Same
self-healing fix applied to the local-flow copy inreleases/version.sh. The
live wekan.fi install page was also corrected to the current version.
Thanks to xet7 and Claude. -
Make the remaining release version substitutions self-healing.
Hardened the last$OLD_VERSION-anchored seds inreleases/version.sh— the
same fragile pattern that froze the DockerARG VERSIONand the install page.
The snapcraft.yaml bundle download was release-critical (same class as the
Docker bug: the snap downloadswekan-<v>-<arch>.zip, so a stale value ships
the wrong bundle under the right name) and was stuck at v9.57; it now anchors
on thewekan-<v>-/releases/download/v<v>/shapes and asserts. The
sandstormappVersionrewrite is now global and self-healing (the redundant
$OLD_NO_DOTS-anchored fixup is dropped), and the Windows Offline.md doc links
self-heal with a soft warning (cosmetic, so they must not fail the release).
snapcraft.yaml and Offline.md were also corrected from their stale v9.57.
Thanks to xet7 and Claude.
Thanks to above GitHub users for their contributions and translators for their translations.
v9.62
v9.62 2026-06-19 WeKan ® release
This release adds the following features:
- Release All Platforms: Fix Docker image showing a stale Admin Panel version (image tagged vX reported v9.57).
The Admin Panel reads the WeKan version from the bundledpackage.json, which
comes verbatim from thewekan-<version>-<arch>.zipthe Dockerfile downloads
and unzips into/build. Thedockerjob never passed--build-arg VERSION,
so every image was built against the Dockerfile's hardcodedARG VERSION
default — and that default was stuck at9.57becausereleases/version.sh
rewrote it with a sed anchored on the old version number, which silently
no-op'd wheneverold_versiondid not match (e.g. the skipped 9.58 numbering).
The result: images tagged v9.59/v9.60/v9.61 shipped the v9.57 bundle and
reported 9.57 in the Admin Panel. Fixed three ways: thedockerjob now passes
--build-arg VERSION=${VERSION}(the release version is authoritative); the
version.shDockerfile rewrite now anchors on the^ARG VERSION=prefix and
asserts the result, so the default can never go stale again; and a new
pre-build guard downloads the release bundle and fails fast if its app
package.jsonversion does not match the release tag, before pushing a
mislabeled image to the registries. Already-pushed v9.58–v9.61 images need a
rebuild to carry their correct contents.
Thanks to xet7 and Claude.
Thanks to above GitHub users for their contributions and translators for their translations.
v9.61
v9.61 2026-06-19 WeKan ® release
This release adds the following features:
- Release All Platforms: Set GH_REPO on the bundle-attach steps so gh finds the repository.
The win64 / mac-arm64 / s390x / ppc64le bundles each finished building but
then failed ongh release uploadwithfailed to run git: fatal: not a git repository.ghtries to detect the target repo from a git remote, but
build-win64checks the repo out intosrc/(so the workspace root is not a
git repository) andbuild-mac-arm64/build-extra-archesdo not check it
out at all. SetGH_REPO=${{ github.repository }}on all three attach steps
soghtargetswekan/wekandirectly without git remote detection. The snap
job is unaffected (it does a full checkout into the workspace root).
Thanks to xet7 and Claude.
Thanks to above GitHub users for their contributions and translators for their translations.
v9.60
v9.60 2026-06-19 WeKan ® release
This release adds the following features:
-
Release All Platforms: Drop armv7l from extra-arch bundles, because Node.js 24 ships no armv7l binaries.
Thebuild-extra-archesarmv7l matrix entry failed withno matching manifest for linux/arm/v7when pullingnode:24-slim. Root cause: Node.js
24 publishes no armv7l (32-bit ARM) binaries at all — neither the official
dist nor unofficial builds — so there is nonode:24arm/v7 image to rebuild
native modules against, and no Node 24 runtime to run such a bundle on an
armv7 device. The armv7l matrix entry is removed; extra-arch bundles are now
s390x + ppc64le. armv7 was already excluded from the Docker image and snap,
so those are unaffected.
Thanks to xet7 and Claude. -
Release All Platforms: Move win64 and mac-arm64 into the post-release extra-platform phase.
build-win64andbuild-mac-arm64were prerequisites of thereleasejob,
so a slow or flaky Windows/macOS runner blocked creation of the GitHub
Release (and thus the Docker and snap jobs, which depend on it). They now
depend onreleaseinstead — alongsidebuild-extra-arches— and each
attaches its ownwekan-<version>-<platform>.zipto the already-created
Release viagh release upload --clobber. The core release now waits only on
the amd64 + arm64 bundles. No build steps changed; only the dependency
wiring, upload mechanism, and section grouping.
Thanks to xet7 and Claude.
Thanks to above GitHub users for their contributions and translators for their translations.
v9.59
v9.59 2026-06-19 WeKan ® release
This release adds the following features:
- Release All Platforms: Fix duplicate mapping keys in generated OpenAPI spec that broke API docs rendering.
The Release All Platforms bump job regeneratespublic/api/wekan.yml
viaopenapi/generate_openapi.pyand then renders it with@redocly/cli,
whose strict YAML parser rejects duplicate mapping keys. The 3-level nested
SimpleSchema inmodels/attachmentStorageSettings.js
(storageConfig.filesystem.enabled,storageConfig.gridfs.enabled, …)
exposed two generator bugs: the sub-schema name was derived from only the
first dotted path segment, collapsingfilesystem.*andgridfs.*leaf
keys (enabled/read/write) into one mapping; and the linear emitter
reopened the parent schema header for each interleaved nested object. The
generator now builds sub-schema names from all leading path segments and
groups each sub-schema's fields contiguously, so deeply nested objects emit
distinct, valid sub-schemas. Output is unchanged for existing 1- and
2-level schemas.
Thanks to xet7 and Claude.
Thanks to GitHub users for their contributions.
v9.57
v9.57 2026-06-19 WeKan ® release
This release fixes the following bugs:
- Fix Docker builds.
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
v9.56
v9.56 2026-06-18 WeKan ® release
This release adds the following updates:
- Updated dependencies.
Merged Dependabot update: dompurify 3.4.9 → 3.4.11
(#6395), a patch update of the
HTML sanitizer used for XSS protection.
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.