Hall of Fame image from https://openclipart.org/detail/120343/trophy
Back to Hall of Fame Contents Back to Wekan Website

Contents / SortBleed

CVE Vulnerability name Date Responsible Security Disclosure by Vulnerabilities
GHSA-xm8x-c8wg-jhmf

SortBleed

2026-07-13 5ud0 / Tarmo Technologies (coordinated disclosure) and xet7 (fix)

Did send detailed report with PoC!
  • 1. SortBleed — a comment-only / read-only board member can escalate to board admin and take over a private board via the sort collection-allow rule (CWE-863 Incorrect Authorization, CWE-269 Improper Privilege Management)
  • CVSS:3.1 8.8 High (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
  • Affected Wekan v9.85 and earlier
  • Fixed at upcoming WeKan release


Details

1. SortBleed — a low-privilege board member can escalate to board admin and take over a private board via the board sort allow rule (CWE-863, CWE-269)

Wekan exposes the Boards MongoDB collection to authenticated DDP clients through Meteor allow/deny rules, so a browser can issue a direct Boards.update(selector, modifier) over the wire. The intended board-document write rule is allowIsBoardAdmin (only a board admin may update a board), reinforced by deny rules that forbid removing the last admin and forbid tampering with the star count.

To support drag-to-reorder on the All Boards / Public Boards pages, a second Boards.allow({ update }) rule was added that returns true for any board member whenever the update touches the sort field:

// server/lib/utils.js (vulnerable)
export function canUpdateBoardSort(userId, board, fieldNames) {
  return !!userId && (fieldNames || []).includes('sort') && allowIsBoardMember(userId, board);
}

// server/permissions/boards.js
Boards.allow({
  update: allowIsBoardAdmin,   // intended board-document write policy
  remove: allowIsBoardAdmin,
  fetch: ['members'],
});
Boards.allow({
  update(userId, board, fieldNames) {
    return canUpdateBoardSort(userId, board, fieldNames);  // true if 'sort' is *among* the fields
  },
  fetch: ['members'],
});
    

Meteor evaluates allow rules with OR semantics and does not scope an approving rule to the field that satisfied it: if any allow callback returns true and no deny callback returns true, the entire modifier is applied to the document. Because canUpdateBoardSort only checked that sort was one of the modified fields (not that it was the only one), a low-privilege board member could smuggle arbitrary board mutations into the same $set as sort. A comment-only or read-only member (a deliberately restricted collaborator with no write access at all) could therefore rewrite members to make themselves board admin, flip a private board's permission to public, change the board title, and evict the legitimate owner — all with a single DDP call:

{$set: {sort: 99, permission: 'public', title: 'PWNED', members: [{userId: attacker, isAdmin: true, isActive: true}]}}
    

The last-admin deny rule did not help because it only inspected $pull operations, so a wholesale $set: { members: [...] } bypassed it entirely.

Attacker model: an authenticated Wekan user who is an active member of the target board in any role — including the most restricted roles (comment-only, read-only, worker), which are explicitly meant to have no ability to modify the board or its membership. No board-admin rights, no global-admin rights, and no victim interaction are required. The only bound on impact is that the attacker must already be a member of the board they take over.

Impact: full board-admin control over a board the attacker was granted only restricted access to — privilege escalation (set isAdmin = true for themselves), board takeover / denial of service to the owner ($set the whole members array to only themselves, evicting the legitimate admin), a confidentiality breach (change permission from private to public, exposing swimlanes, lists, cards, comments, attachments and the member list — public boards are world-readable in Wekan), and arbitrary integrity changes (title, color, settings). Once board admin, the attacker inherits every board-admin capability (adding integrations / outgoing webhooks, adding/removing members, archiving or deleting the board, changing everyone's roles). Confirmed at runtime by the reporter against a local instance (v9.84 image; the vulnerable code is byte-identical across v9.84, v9.85 and main): the control call (a members rewrite without sort) was correctly denied with 403 Access denied, while the identical rewrite with sort:99 added was accepted.

Fix

The sort-reorder allow rule is now restricted to updates that touch only the sort field (and nothing else), so it can never approve a modifier that also mutates members, permission, title or any other field:

// server/lib/utils.js (fixed)
export function canUpdateBoardSort(userId, board, fieldNames) {
  const fields = fieldNames || [];
  return !!userId && fields.length === 1 && fields[0] === 'sort' && allowIsBoardMember(userId, board);
}
    

With sort required to be the sole modified field, the only remaining allow rule for a multi-field board update is allowIsBoardAdmin, which a comment-only / read-only member fails — so the whole modifier is rejected. As defense in depth, the last-admin deny rule in server/permissions/boards.js now also rejects a $set rewrite of the members array that would drop the last active admin, not just a $pull. A regression test in server/lib/tests/boards.security.tests.js covers the multi-field smuggling case (['sort', 'members'], ['sort', 'permission', 'title'], etc.). The legitimate All Boards / Public Boards drag-reorder is unaffected: it persists the manual order per-user in profile.boardSortIndex (Users.setBoardSortIndex), not in the board document.



Timeline Details
2026-07-13 Report received from 5ud0 / Tarmo Technologies (coordinated disclosure, GHSA-xm8x-c8wg-jhmf).
upcoming release Fixed at upcoming WeKan release, by restricting the board sort allow rule to updates that touch only the sort field, so a board member can no longer smuggle members/permission/title changes into the same modifier.


Back to Hall of Fame Contents Back to Wekan Website