| CVE | Vulnerability name | Date | Responsible Security Disclosure by | Vulnerabilities |
|---|---|---|---|---|
|
GHSA-gv8h-5p3p-6hx7
|
ChecklistBleed |
2026-06-20 |
DavidCarliez (coordinated disclosure) and Claude (fix)
![]() Did send detailed report with PoC! |
|
WeKan boards are membership-scoped: a private board is only readable/writable by its active
members. Checklists and checklist items are attached to a card and carry a denormalized
boardId (so the board publication can filter them with a single reactive cursor).
They are moved between cards by setting a new cardId (and, for items, a new
checklistId) in an update; a server Checklists.before.update hook then
re-derives boardId from the destination card.
The DDP collection write policies for Checklists and ChecklistItems authorize an update by
checking only the current (pre-update) cardId of the document and asking
whether the caller has write access to that card's board. They never validate the
new destination (cardId, checklistId or boardId)
supplied in the update modifier.
// server/permissions/checklists.js
Checklists.allow({
async update(userId, doc) {
return await allowIsBoardMemberWithWriteAccessByCard(userId, await Cards.findOneAsync(doc.cardId));
}, // <-- doc.cardId = SOURCE card
fetch: ['userId', 'cardId'],
});
// server/permissions/checklistItems.js has the same pattern.
Because every logged-in user can create their own board (where they are a write-capable
member), an attacker can create a checklist or checklist item on their own card and then, in a
single /checklists/update or /checklistItems/update DDP call,
$set its cardId to a card in a victim's private board. The allow rule
sees the attacker's own source card, approves the write, and the
Checklists.before.update hook denormalizes boardId from the
destination card — so the attacker-controlled checklist/item becomes attached to the victim's
private board's publication/query model. The only practical precondition is knowledge of a
target private card id; board membership is not required.
The protected moveChecklist Meteor method
(server/models/checklists.js) correctly checks board membership on
both the source and the destination card:
if (!(await allowIsBoardMemberByCard(this.userId, sourceCard))) {
throw new Meteor.Error('not-authorized', 'Not authorized to move checklist from source card');
}
if (!(await allowIsBoardMemberByCard(this.userId, newCard))) {
throw new Meteor.Error('not-authorized', 'Not authorized to move checklist to target card');
}
But a DDP client can simply bypass that method and update the collections directly over the Meteor websocket, where only the (source-only) allow rules applied.
Impact: a low-privileged authenticated user could inject attacker-controlled checklist
and checklist-item data (titles, completion state) into any private board by target
card id, defeating board-level access control. This is the same class as
BoardBleed (GHSA-gm7v-pc38-53jr), which had only fixed the
boardId-based cross-board move for Cards/Lists/Swimlanes; Checklists and
ChecklistItems move via cardId/checklistId and were not covered.
The server-side moveChecklist Meteor method validates both source and destination
board membership, and server-side trusted code bypasses allow/deny entirely. Only the DDP
allow/deny layer, reachable directly over the Meteor websocket by any authenticated client,
was vulnerable.
Two helpers, denyCrossBoardMoveByCard(userId, modifier) and
denyCrossBoardMoveByChecklistItem(userId, modifier), were added in
server/lib/utils.js, and a deny update rule was added to
each of Checklists and ChecklistItems
(server/permissions/checklists.js, server/permissions/checklistItems.js).
The deny rule inspects the update modifier and rejects the move unless the caller has write
access (active, write-capable member) on the destination board — resolved from the new
boardId, the new cardId's card, or (for items) the new
checklistId's checklist → card. An unknown/missing destination fails closed. A
cross-board checklist move is therefore now only permitted into a board where the user is
genuinely a write-capable member, while same-card edits and legitimate moves between boards the
user belongs to keep working. A regression test
(server/lib/tests/checklistbleed.security.tests.js) was added.
| Timeline | Details |
|---|---|
| 2026-06-20 |
Report received from DavidCarliez (coordinated disclosure, GHSA-gv8h-5p3p-6hx7). |
| Upcoming release | Fixed at the upcoming WeKan release, by denying any DDP update that moves a Checklist/ChecklistItem to a destination board the caller has no write access to. |