| CVE |
Icon |
Vulnerability name |
Date |
Responsible Security Disclosure
by
|
Stars |
Process |
Vulnerabilities |
| - |
|
SubtaskDepositBleed |
2026-09-14 |
Wenhao Wu, Southeast University |
     |
Process
Responsible disclosure through a saved GitHub security advisory; current code and sibling paths reviewed during remediation.
|
Details
An unvalidated deposit pointer bridged private cards and related content into the source board feed, and subtask creation skipped destination write authorization. Source card scopes now exclude foreign pointers and null IDs. Deposit content follows a reactive authorized board cursor with its own assignment restrictions. Assigned-card content follows reactive card cursors. Writes and pointer changes require destination write access. Write refusals are summarized in Problems; ordinary filtered reads are not attack events. Source fix and regression coverage. Targeted tests pass; live browser execution remains pending. No CVE is assigned here. More details
|
| - |
|
LinkedWriteBleed |
2026-09-14 |
Wenhao Wu, Southeast University |
     |
Process
Responsible disclosure through a saved GitHub security advisory; current code and sibling paths reviewed during remediation.
|
Details
Comment-only source members could create links on self-owned boards and use delegated write checks to modify the source. Source write access is now required for method and DDP link creation and pointer changes. Explicit non-writing source roles cap delegation through legacy links. UI permissions follow the ceiling. Denied attempts use bounded Problems summaries. Source fix and regression coverage. Targeted tests pass; live browser execution remains pending. No CVE is assigned here. More details
|
| - |
|
InvitationBoardBleed |
2026-09-14 |
Wenhao Wu, Southeast University |
     |
Process
Responsible disclosure through a saved GitHub security advisory; current code and sibling paths reviewed during remediation.
|
Details
When domain-approved users could send registration invitations, the supplied board list was stored without board authorization. The complete list now requires existing boards and the same configured inviter-role policy as board invitations, with a site-admin bypass. Denied grants are summarized in Problems. Live mail delivery and redemption remain unverified. Source fix and regression coverage. Targeted tests pass; live browser execution remains pending. No CVE is assigned here. More details
|
| - |
|
InviteProfileBleed |
2026-09-14 |
Wenhao Wu, Southeast University |
     |
Process
Responsible disclosure through a saved GitHub security advisory; current code and sibling paths reviewed during remediation.
|
Details
Removed members could forge profile.invitedBoards and call acceptInvite to reactivate their retained membership row. Client permission gates now protect that capability, including operator paths, parent replacement and rename destinations. Ordinary leaf preferences remain editable. Denied invitation changes appear as bounded Problems summaries; logging cannot break refusal. Source fix and regression coverage. Targeted tests pass; live browser execution remains pending. No CVE is assigned here. More details
|
| - |
|
RuleButtonBleed |
2026-09-14 |
Wenhao Wu, Southeast University |
     |
Process
Responsible disclosure through a saved GitHub security advisory; current code and sibling paths reviewed during remediation.
|
Details
Manual button rules accepted non-writing members and unbound card IDs. Both the method and shared action dispatcher now require write access and authoritative card-to-rule board binding before executing actions. Cardless board buttons remain supported. Denied contexts are summarized in Problems; logging cannot break refusal. Source fix and regression coverage. Targeted tests pass; live browser execution remains pending. No CVE is assigned here. More details
|
| - |
|
ManageBoardBleed |
2026-09-14 |
Wenhao Wu, Southeast University |
     |
Process
Responsible disclosure through a saved GitHub security advisory; current code and sibling paths reviewed during remediation.
|
Details
REST management endpoints incorrectly accepted ordinary write capability. Title, card-settings and rule mutation endpoints now require board or site administrator privileges, aligning with DDP. Unauthorized management attempts are summarized in Problems; logging cannot break refusal. Source fix and regression coverage. Targeted tests pass; live browser execution remains pending. No CVE is assigned here. More details
|
| - |
|
CommentBoundaryBleed |
2026-09-14 |
Wenhao Wu, Southeast University |
     |
Process
Responsible disclosure through a saved GitHub security advisory; REST and DDP comment boundary paths reviewed during remediation.
|
Details
- Comment insertion failed to bind cards to the authorized board (CWE-639).
- REST and DDP inserts now validate the card board; DDP identity rebinding is denied. Denials are summarized in Admin Panel Problems.
- More details
|
| - |
|
MutationBleed |
2026-09-14 |
Wenhao Wu, Southeast University |
     |
Process
Responsible disclosure through a saved GitHub security advisory; membership-only method guards and their siblings reviewed during remediation.
|
Details
- Membership-only method guards allowed non-writing roles to mutate board data (CWE-863).
- List, swimlane and checklist moves, scoped imports, attachment renames and history writes now enforce the canonical write capability. Denials are summarized in Admin Panel Problems.
- More details
|
| - |
|
VisibilityBleed |
2026-09-14 |
Wenhao Wu, Southeast University |
     |
Process
Responsible disclosure through a saved GitHub security advisory; sibling path found during remediation.
|
Details
- Server methods bypassed the private-only board visibility policy (CWE-863).
- Board creation and card-to-board conversion now force private visibility when required, recording blocked overrides in Admin Panel Problems.
- More details
|
| - |
|
WipeBleed |
2026-09-09 |
xet7 |
     |
Process
Found and fixed during an internal security review of Attachments/Avatars (ostrio:files) upload, download and removal authorization.
|
Details
- SubtaskDepositBleed — ostrio:files' own
_FilesCollectionRemove_attachments/_FilesCollectionRemove_avatars DDP methods bypass Attachments.allow/Avatars.allow entirely, so any anonymous connection could call one with selector {} and delete every attachment or avatar on the instance (CWE-862 Missing Authorization)
- Both now require
this.userId and check every matched file: attachments need the caller's board-write access, avatars need ownership or site-admin status
- Fixed at upcoming WeKan release
- More details
|
| - |
|
UploadPathBleed |
2026-09-09 |
xet7 |
     |
Process
Found and fixed during an internal security review of Attachments/Avatars (ostrio:files) upload, download and removal authorization.
|
Details
- UploadPathBleed — the attachment upload
namingFunction used a client-supplied fileId verbatim as the on-disk file name, and sanitize() was an identity function, so an anonymous upload with fileId: "../../../../tmp/pwn" could write attacker-controlled content anywhere the WeKan process can write (CWE-22 Path Traversal, CWE-434 Unrestricted Upload, CWE-306 Missing Authentication)
sanitize() is restored to the same whitelist models/avatars.js already used, and namingFunction now also validates the fileId against the ObjectId shape WeKan itself generates
- Fixed at upcoming WeKan release
- More details
|
| - |
|
PortraitBleed |
2026-09-09 |
xet7 |
     |
Process
Found and fixed during an internal security review of Attachments/Avatars (ostrio:files) upload, download and removal authorization.
|
Details
- PortraitBleed — unlike Attachments, Avatars never set a
protected callback, so ostrio:files' own library-native download route (whose default lets everything through when protected is unset) served any avatar to any anonymous caller, bypassing isAuthorizedForAvatar entirely (CWE-862 Missing Authorization, CWE-284 Improper Access Control)
Avatars.protected now mirrors Attachments.protected: an authenticated caller may always view an avatar; an anonymous one only when the avatar's owner is a member of a public board
- Fixed at upcoming WeKan release
- More details
|
| - |
|
RelicAvatarBleed |
2026-09-09 |
xet7 |
     |
Process
Found and fixed during an internal security review of Attachments/Avatars (ostrio:files) upload, download and removal authorization.
|
Details
- RelicAvatarBleed — both legacy CollectionFS avatar fallback routes in
server/routes/avatarServer.js streamed a migrated-in avatar to anyone who knew its old cfs.avatars.filerecord id, one of them with no authentication check at all (CWE-862 Missing Authorization)
- Both routes now require a signed-in caller; the anonymous public-board redirect for already-migrated avatars is untouched
- Fixed at upcoming WeKan release
- More details
|
| GHSA-crq2-phg8-4xvg |
|
SheetColorBleed | 2026-09-05 |
rbbjinioeq and xet7 |
     |
Process
Coordinated disclosure through a GitHub security advisory, reproduced against the vendored XLSX parser and sheet-tab CSS serialization.
|
Details
- An XLSX sheet tab color could append arbitrary CSS declarations in another member's authenticated preview (CWE-79, CWE-116)
- Only canonical six-digit hexadecimal colors now reach the style serializer
- Malformed, short, alpha and declaration-bearing values are discarded
- More details
|
| GHSA-rv5g-5p4g-3v89 |
|
MimeStorageBleed | 2026-09-01 |
avrlab233 and xet7 |
     |
Process
Coordinated disclosure through a GitHub security advisory, reproduced against upload validation and the original Meteor-Files route on every storage backend.
|
Details
- A slash-separated unquoted event handler bypassed markup sniffing (CWE-79)
- Filesystem uploads skipped migration-only validation
- Executable stored metadata could be served inline by Meteor-Files
- All storage paths now reject or sandbox active attachment content
- More details
|
| GHSA-8phm-9rqm-v9hc |
|
CookieTokenBleed | 2026-08-29 |
binary-lover and xet7 |
    |
Process
Coordinated disclosure through a GitHub security advisory, then verified against Meteor 3.5's maintained native HttpOnly resume-token flow.
|
Details
- Persistent session credentials were readable to browser scripts (CWE-1004)
- Meteor's native HttpOnly resume-cookie flow replaces custom synchronization
- Persistent Web Storage credentials are disabled
- More details
|
| GHSA-hp9m-vff5-7pvw |
|
MailTitleBleed | 2026-08-29 |
binary-lover and xet7 |
    |
Process
Coordinated disclosure through a GitHub security advisory, traced from stored activity values through localization to HTML email delivery.
|
Details
- Stored activity titles could become active email markup (CWE-79)
- The completed localized body is escaped at its final HTML boundary
- Notification subjects discard header-injecting newlines
- More details
|
| GHSA-33h9-rc5h-667p |
|
SearchBleed | 2026-08-29 |
crypto-nidh and xet7 |
     |
Process
Coordinated disclosure through a GitHub security advisory, reproduced against the global-search DDP publication and its stored pagination selectors.
|
Details
- Authenticated clients could replace the server's board-scoped search selector (CWE-943)
- Execution operators are rejected before database access
- Initial and stored pagination selectors are constrained to current board access
- More details
|
| GHSA-9w4x-hf2r-hc9v |
|
RuleBleed | 2026-08-29 |
crypto-nidh and xet7 |
     |
Process
Coordinated disclosure through a GitHub security advisory, verified against DDP-created, scheduled and legacy automation paths.
|
Details
- Server-side automation bypassed the collection cross-board deny hook (CWE-862, CWE-863)
- Rule registration and execution now independently enforce destination write access
- Authorization runs before destination list or swimlane lookup, removing the private-structure oracle
- Denied attempts are summarized in Admin Panel → Problems
- More details
|
| GHSA-4mjm-vj9f-p629 |
|
AvatarMimeBleed | 2026-08-28 |
crypto-nidh and xet7 |
     |
Process
Coordinated disclosure through a GitHub security advisory, reproduced against both current and legacy avatar routes.
|
Details
- Stored browser-executable avatar MIME types could render active content under the WeKan origin (CWE-79, CWE-434)
- Dangerous types are now sandboxed opaque downloads with nosniff and frame denial
- No Problems event is emitted because legitimate avatar views use the same response path
- More details
|
| GHSA-xcxp-hx9w-q5q9 |
|
LegacyAttachBleed | 2026-08-28 |
crypto-nidh and xet7 |
     |
Process
Coordinated disclosure through a GitHub security advisory, reproduced against the CollectionFS-compatible attachment route.
|
Details
- Legacy HTML, XML and JavaScript attachments lacked the protections already applied to SVG files (CWE-79, CWE-693)
- All browser-executable types now receive the same opaque, sandboxed download policy
- No Problems event is emitted because legitimate legacy downloads use the same response path
- More details
|
| GHSA-2x89-6mq2-834r |
|
SwimlaneBleed | 2026-08-28 |
crypto-nidh and xet7 |
     |
Process
Coordinated disclosure through a GitHub security advisory, reproduced with a read-only board member calling the Meteor method directly.
|
Details
- Read-only members could create a default swimlane through a method guarded only by read membership (CWE-862)
- The method now requires the shared board write capability
- Denied attempts are summarized in Admin Panel → Problems
- More details
|
| - |
|
HostnameBleed | 2026-08-27 |
GitHub CodeQL (code scanning alerts #435 and #436) and xet7 |
  |
Process
Automated code scanning flagged hostname examples used as incomplete regular expressions.
|
Details
- Unescaped dots made two tenant-hostname translation assertions accept non-literal matches (CWE-20)
- The affected code was test-only and had no runtime exposure or attributable Problems event
- Exact literal comparisons and a repository-wide negative guard prevent recurrence
- More details
|
| GHSA-5gcv-2hhj-7rg9 |
|
SessionBleed | 2026-08-27 |
crypto-nidh and xet7 |
     |
Process
Coordinated disclosure through a GitHub security advisory, reproduced against the unauthenticated global-search pagination publications.
|
Details
- Reused search session IDs could disclose private cross-board card data (CWE-639, CWE-862)
- Denied logged-out probes are summarized in Admin Panel → Problems
- More details
|
| GHSA-xwv8-m73h-68vg |
|
ClaimBleed | 2026-08-26 |
crypto-nidh and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, validated against trusted userinfo and attacker-controlled access-token claims. |
Details- Whitelisted OIDC claims could replace account identity and service-owned token fields (CWE-863, CWE-566)
- No Problems event is emitted because legitimate OIDC logins use the same claim-processing path
- More details
|
| GHSA-5r3j-h65h-fg22 |
|
MembershipBleed | 2026-08-26 |
crypto-nidh and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, reproduced against the unauthenticated DDP publication. |
Details- Logged-out clients could enumerate authentication methods, teams and organizations (CWE-200)
- Denied attempts are summarized in Admin Panel → Problems
- More details
|
| GHSA-9cgp-m28v-64xv |
|
ResetBleed | 2026-08-26 |
crypto-nidh and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, reproduced against Meteor's unauthenticated account-recovery methods. |
Details- Unbounded password recovery and verification calls enabled email flooding and repeated token attempts (CWE-307, CWE-799)
- Rate-limit denials are summarized in Admin Panel → Problems
- More details
|
GHSA-88mv-h439-rj8j GHSA-9846-cj96-6hv5 |
|
UserSearchBleed | 2026-08-25 |
Char0n1507, Reload3d and xet7 |
     |
ProcessTwo coordinated GitHub security advisories were validated together against both user-search DDP paths. |
Details- User search disclosed private account metadata and evaluated attacker-controlled regular expressions (CWE-284, CWE-359, CWE-400, CWE-1333)
- No Problems event is emitted because legitimate searches use the same path
- More details
|
| GHSA-c3ch-34g5-x3x7 |
|
MiniProfileBleed | 2026-08-25 |
Char0n1507 and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, validated against the unauthenticated DDP publication. |
Details- Logged-out clients could enumerate user profile and membership metadata (CWE-306, CWE-359)
- Denied attempts are summarized in Admin Panel → Problems
- More details
|
| GHSA-5fc2-m4gw-j6qq |
|
PositionHistoryBleed | 2026-08-25 |
Char0n1507 and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, validated at insertion, method and model boundaries. |
Details- Forged undo history could inject a card into another private board (CWE-284, CWE-639)
- Denied attempts are summarized in Admin Panel → Problems
- More details
|
| GHSA-hvvr-j425-5xxm |
|
SubtaskExportBleed | 2026-08-25 |
Char0n1507 and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, validated across JSON, ZIP, Excel and PDF exports. |
Details- Parent-only subtask queries could export private-board card data across board boundaries (CWE-200, CWE-639)
- No Problems event is emitted because legitimate exports use the same path
- More details
|
| GHSA-5797-pjx8-9h6m |
|
CasAccountMergeBleed | 2026-08-25 |
Char0n1507, crypto-nidh and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, compared with WeKan's explicit LDAP and OIDC merge controls. |
Details- A matching CAS username could take over an existing non-CAS account without merge consent (CWE-287, CWE-863)
- Denied attempts are summarized in Admin Panel → Problems
- More details
|
| GHSA-qp32-wqxw-wq3h |
|
ImportBleed | 2026-08-23 |
Char0n1507 and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, validated against the current DDP import methods and their direct database write chain. |
Details- Logged-out DDP clients could write imported board data and placeholder users (CWE-306)
- More details
|
| GHSA-5r4m-5xx6-96jf |
|
ChecklistWriteBleed | 2026-08-22 |
Char0n1507 and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, validated against current REST handlers. |
Details- Read-only members could mutate checklist content (CWE-863)
- More details
|
| GHSA-5r57-9vj7-c64f |
|
TokenAuditBleed | 2026-08-22 |
Char0n1507 and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, validated against current REST handlers. |
Details- Administrator token issuance bypassed impersonation auditing (CWE-778)
- More details
|
| GHSA-6jvj-85q3-6q2m |
|
OwnerBleed | 2026-08-22 |
Char0n1507 and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, validated against current REST handlers. |
Details- Board creation trusted client-selected ownership (CWE-639)
- More details
|
| GHSA-cp24-5m9m-wm97 |
|
RoleBleed | 2026-08-22 |
senti-man and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, validated against current REST handlers. |
Details- REST capabilities drifted from the canonical role table (CWE-863)
- More details
|
| GHSA-h59p-76c3-8345 |
|
ErrorBleed | 2026-08-22 |
Char0n1507 and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, validated against current REST handlers. |
Details- Raw errors were returned as successful REST responses (CWE-209)
- More details
|
| GHSA-qf5c-63jx-mpv4 |
|
CommentWriteBleed | 2026-08-22 |
Char0n1507 and xet7 |
     |
ProcessCoordinated disclosure through a GitHub security advisory, validated against current REST handlers. |
Details- Comment permission allowed card and checklist creation (CWE-863)
- More details
|
|
GHSA-p4cq-83j9-7g73
|
|
TenantBleed |
2026-08-21 |
Char0n1507 and xet7
|
   
|
Process
Coordinated disclosure through a GitHub security advisory, with insert, update and remove reproduced on both collections.
|
Details
- SheetColorBleed — authenticated users could mutate self-ID Organization and Team configuration because a matching document id was treated as administrative authority (CWE-563, CWE-862)
- All six DDP collection operations now share one site-admin-only decision; denied attempts appear in Admin Panel → Problems
- Fixed at upcoming WeKan release
- More details
|
|
GHSA-f396-42fx-vr88
|
|
AssignedBleed |
2026-08-21 |
Char0n1507 and xet7
|
   
|
Process
Coordinated disclosure through a GitHub security advisory, with a working v11.06 reproduction and root-cause analysis of the missing role flag.
|
Details
- AssignedBleed — Only Assigned Comment members could modify unassigned cards through REST because the shared write check omitted their role flag instead of consulting the canonical capability table (CWE-863 Incorrect Authorization)
- Moderate intra-board integrity impact; no cross-board access, confidentiality impact or administrator escalation was observed
- The shared REST and attachment write checks now use the canonical capability decision; denied attempts appear in Admin Panel → Problems
- Fixed at upcoming WeKan release
- More details
|
|
GHSA-fpm6-r5fg-2mrg
|
|
CalendarBleed |
2026-08-21 |
Char0n1507 and xet7
|
   
|
Process
Coordinated disclosure through a GitHub security advisory, with a working v11.06 reproduction and the canonical authorization helper identified.
|
Details
- CalendarBleed — Comment Only, Only Assigned Comment and Worker members could create arbitrary cards by calling the iCalendar import Meteor method, because it excluded read-only flags instead of requiring the canonical write capability (CWE-863 Incorrect Authorization)
- Moderate intra-board integrity impact; no cross-board access, confidentiality impact or administrator escalation was observed
- The DDP method now uses the same shared write-access decision as its REST sibling, with regression coverage for all five non-writing roles and all four writing roles
- Fixed at upcoming WeKan release
- More details
|
-
|
|
RouteBleed |
2026-08-17 |
GitHub CodeQL (code scanning alert #434) and xet7
|
 
|
Process
Automated code scanning flagged incomplete regular-expression escaping.
|
Details
- RouteBleed — a board-export regression test interpolated a route path into a dynamic regular expression after escaping only forward slashes. Backslashes and every other regular-expression metacharacter remained active, so the generated pattern could mean something different from the literal route it was meant to find (CWE-20 Improper Input Validation, CWE-80 Improper Neutralization of Script-Related HTML Tags in a Web Page, CWE-116 Improper Encoding or Escaping of Output)
- GitHub CodeQL code scanning alert #434, rule
js/incomplete-sanitization, severity High
- The affected code runs only in
tests/boardExportScope.test.cjs over hardcoded export paths. It is not shipped application code and accepts no request or user input, so there was no runtime exposure and no attributable attempt to record in Admin Panel → Problems
- Fixed by removing the dynamic
RegExp and checking for the exact route literal with String.prototype.includes(). A repository guard rejects the reported slash-only escape shape everywhere, and its negative case includes a backslash and the complete regular-expression metacharacter set
- Fixed at upcoming WeKan release
- More details
|
GHSA-rf3w-rj48-jxcc
|
|
JamBleed |
2026-08-16 |
daniais and xet7
|
   
|
Process
Coordinated disclosure through a GitHub security advisory, with a lab reproduction on v10.91, an A/B harness against a patched build, a CVSS assessment the reporter marked as preliminary and offered for independent review, and a 90-day window offered rather than assumed.
|
Details
- JamBleed — the brute-force lockout counted an attacker's failed logins against the VICTIM'S ACCOUNT rather than against the address they came from, so anyone who knew a username could lock its owner out of login from every address, repeatably (CWE-307 Improper Restriction of Excessive Authentication Attempts)
- Usernames are public in normal WeKan use — board and card members are listed — so choosing a target was trivial, and an administrator was as easy to lock out as anyone else. Walking the member list locks out an entire instance
- A CORRECT password was refused while the lock held, and counted as a further failure on the way. The old code allowed an attempt only when there was no error AND no lock, so the owner typing the right password fell through to the same refusal as the attacker
- Affected from v10.59, and not before: the flat counter is much older, but until the LockoutBleed fix (GHSA-2g94-9x3m-hv37) the hooks gated on English error strings that Meteor's
ambiguousErrorMessages had already rewritten, so the counter never moved and no account ever locked. Making the lockout work is what made this reachable
- No confidentiality or integrity impact: nothing is disclosed and nothing is modified. The loss is the availability of authentication for a chosen user, sustained for as long as the attacker keeps going
- The counter is per (user, source address) now, keyed by a SHA-256 prefix so a locked account carries no list of the addresses that attacked it, and a correct password is allowed FIRST — before anything reads the lock — and clears the state behind it. Hammering during a lock no longer extends it
- Fixed at upcoming WeKan release
- More details
|
—
|
|
SignupBleed |
2026-08-16 |
AhmedLukman and xet7
|
 
|
Process
Found while reviewing a pull request about the opposite symptom.
|
Details
- SignupBleed — with registration turned OFF in the Admin Panel,
POST /users/register created accounts anyway and handed back a login token, because its guard read a Meteor option WeKan never sets (CWE-862 Missing Authorization)
- The Admin Panel switch closed the sign-up FORM and nothing else. A closed instance answered the REST endpoint exactly as an open one did, so anybody who could reach the port could make an account on it
- The guard read
Accounts._options.forbidClientAccountCreation. WeKan's only Accounts.config() call sets loginExpirationInDays and nothing else; forbidClientAccountCreation: disableRegistration is passed to AccountsTemplates.configure(), which is the useraccounts package's own options object; and that value is assigned from an async Meteor.call('isDisableRegistration') callback that fires after configure() has already run. Three near-misses, and the condition was always false
- No credentials were exposed and no existing data was reachable: the fault is that an instance whose administrator had closed registration kept accepting new accounts. Affects deployments with
WITH_API=true
- The endpoint now reads
getCurrentSetting().disableRegistration, the same field the sign-up form's own Meteor method reads, so the form and the API cannot disagree. A refusal is recorded and shows in Admin Panel / Problems — every call that reaches it is an attempt, because the administrator has turned registration off
- Fixed at upcoming WeKan release
- More details
|
GHSA-8cqr-x6m5-v4w6
|
|
PurgeBleed |
2026-08-15 |
ybsun0215 and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-8cqr-x6m5-v4w6.
|
Details
- PurgeBleed — the single-card DELETE authorised the caller on the board in
:boardId and then fetched the card by :cardId ALONE, so the child-removal it runs first erased the checklists, checklist items, comments, activity history and subcard tree of any card in the instance (CWE-639 Authorization Bypass Through User-Controlled Key, CWE-862 Missing Authorization)
- The destruction happens BEFORE the card is removed, so the unconstrained lookup is the whole vulnerability:
cardRemover erases everything keyed on whatever card id came back. The removal that follows uses a triple key — {_id, listId, boardId} — so a foreign card was never actually removed, which is why the card SHELL survived and made the damage easy to miss
- The endpoint answered HTTP 200 with the card id either way, so nothing in the response said that a caller had just destroyed the contents of a card on a board they cannot read. Deletion is irreversible, and the attack is repeatable for every foreign card id an attacker learns
- Any authenticated user with write access to ONE board — their own is enough — could reach every board on the instance. All deployments with
WITH_API=true are affected
- The bulk endpoint
DELETE .../cards/bulk had always constrained its lookup with getCard({ _id, boardId }). The single-card path is the sibling that was missed, the same shape as PassBleed (GHSA-6p5m-f9p2-wqm5) and the REST-side sibling of GHSA-gm7v-pc38-53jr. It uses the constrained lookup now, so a card outside the authorised board simply does not resolve
- Fixed at upcoming WeKan release
- More details
|
GHSA-6qpx-x7vr-p9w6
|
|
HashBleed |
2026-08-15 |
ybsun0215 and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-6qpx-x7vr-p9w6.
|
Details
- HashBleed —
GET /api/users/{userId} and PUT /api/users/{userId} serialised the whole Meteor user document, so every answer carried services.password.bcrypt and the hash of every live session token (CWE-200 Exposure of Sensitive Information)
- The authorisation was never the problem: both endpoints are admin-only and stayed that way. The PAYLOAD was. Walking the ids that
GET /api/users returns harvested the offline crackable password hash and the session-token hashes of every account on the instance
- A password hash is an offline attack that does not touch the server, and it survives long after the export. The session material is
services.resume.loginTokens[], one entry per live session with the time it began
- The two sibling endpoints in the same file show what was intended:
GET /api/users projects down to _id and username, and GET /api/user, the self view, runs delete data.services before answering. Nothing in the code, the CHANGELOG or the documentation ever said the subtree was meant to be exposed
- One helper strips
services and sessionData now, and both endpoints answer through it — the PUT as well, which returned the same unprojected document after every action branch
- Fixed at upcoming WeKan release
- More details
|
GHSA-whxm-pxgj-7wqv
|
|
GuestBleed |
2026-08-15 |
ybsun0215 and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-whxm-pxgj-7wqv.
|
Details
- GuestBleed — the
members and assignees ARRAYS on card create and card update were stored exactly as given, so a member of a private board could put any user id on a card, and GET /api/user/cards then fed that outsider the private board's card titles, ids and dates (CWE-639)
- Two paths combine. Nothing validated that the ids in the arrays belong to the card's board, and the listing endpoint answered by CARD membership without re-checking access to the card's BOARD — so being named on a card was enough to read from a board that refuses to open
- The outsider's direct read of the board stayed Forbidden the whole time, which is what made this quiet: every ordinary check still said no, while the "my cards" feed kept answering. It is continuous, not a single disclosure — the feed follows the card
- The invariant already existed and was documented on the merge endpoint
POST .../cards/{cardId}/members/{memberId}, which has refused a non-member with 400 since issue #5998. The array form on POST and PUT bypassed it, for both members and assignees
- Both halves are fixed: every id in either array is checked with the same
canAssignCardMember the merge endpoint uses, on single create, bulk create and update alike; and the listing filters by the boards the caller is an active member of, so a card placed before this release stops answering too
- Fixed at upcoming WeKan release
- More details
|
GHSA-r8r3-23vr-8jh6
|
|
StaleBleed |
2026-08-15 |
ybsun0215 and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-r8r3-23vr-8jh6.
|
Details
- StaleBleed — the board listing matched
'members.userId' with a dotted path, which ignores the membership's isActive flag, so a removed member kept seeing the board's id and title indefinitely (CWE-863 Incorrect Authorization)
- Removing a board member does not delete their entry: it sets
isActive: false and isAdmin: false and keeps it. A query that matches the entry without reading that flag therefore matches revoked members exactly as it matches current ones
- Reading the board itself was already refused, so the exposure is the board's id and its title — but the id is the part that matters, because it is what every other endpoint in the API is addressed by, and the title is often the thing a private board is private about
- This is the same class as GHSA-gwc4-fw7p-gw58 (org, team and domain shares, fixed in 10.74), whose fix introduced one builder for board visibility with the header note "A share entry counts only while it is active, everywhere". This listing endpoint predates that consolidation and was never converted
- It uses
$elemMatch now, so the userId and the active flag have to be true of the SAME entry — which is what a revoke means everywhere else in WeKan
- Fixed at upcoming WeKan release
- More details
|
GHSA-6jr3-42jf-vhm5
|
|
AuthorBleed |
2026-08-15 |
ybsun0215 and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-6jr3-42jf-vhm5.
|
Details
- AuthorBleed — six server paths took the actor's identity from the request body's
authorId field, checking only that such a user exists, so a board member could record card creations, card deletions and custom fields as somebody else (CWE-345 Insufficient Verification of Data Authenticity)
- The board's own history is the thing at stake. "victim created this card" and "victim deleted this card" became attacker-controlled sentences, on any board the caller may write to, and the card document itself recorded the forged
userId as its creator
- The six: single card create, bulk card create, linked-card create, single card delete, bulk card delete, and custom-field create
- WeKan had already accepted this exact class as a vulnerability and fixed it for card comments in 8.19, and again for the card PUT handler — whose inline note still reads "use req.userId consistently (it previously read req.body.authorId here)". These six paths were missed, which makes it an incomplete fix rather than a new decision
- All six read
req.userId now — the session the request authenticated as, which is the only identity the server can vouch for. The parameter does appear in historical API documentation, but that documentation predates the 8.19 fix of the same pattern
- Fixed at upcoming WeKan release
- More details
|
GHSA-6p5m-f9p2-wqm5
|
|
PassBleed |
2026-08-11 |
TWPaMWang and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-6p5m-f9p2-wqm5.
|
Details
- PassBleed — the single-card Excel export authorised against one identifier and read its data using another.
GET /api/boards/:boardId/lists/:listId/cards/:cardId/exportExcel checked whether the caller could see the board in :boardId, then resolved the card by :cardId alone, with nothing tying the two together (CWE-639 Authorization Bypass Through User-Controlled Key, CVSS 6.5)
- So
:boardId became a reusable ACCESS PASS and :cardId alone decided what came back. The pass is self-service: POST /api/boards takes permission straight from the request body, so any authenticated user could mint their own PUBLIC board, name it as :boardId, and pass the id of a card in somebody else's private board. :listId was never used in a query at all and could be any string
- The workbook that came back carried the victim card's title, full description, members and assignees, every comment with its author, checklists and checklist items, subtask titles, attachment metadata — and, because image attachments are read through
getReadStream() and embedded with workbook.addImage, the attachment BYTES. One board could be reused while :cardId was substituted freely, which made it a scriptable bulk read rather than a single disclosure
- The same route shape for PDF had always been right:
ExporterCardPDF resolves getCard({ _id, boardId, listId }) and returns 404 for a cross-board id. That control in the same codebase is what shows this was an omission rather than a decision, and it is the fix — the Excel exporter now uses the same constrained lookup, so a card outside the authorised board does not resolve at all and the checklist, subtask, comment and attachment fan-out keyed on that card id can reach nothing. The route binds the two identifiers as well, before either branch builds, including the public branch that skips authentication entirely
- Fixed at upcoming WeKan release
- More details
|
GHSA-phm4-4v26-j2vq
|
|
WhereBleed |
2026-08-11 |
TungNGo02 and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-phm4-4v26-j2vq.
|
Details
- WhereBleed — eight Admin Panel handlers took a MongoDB query selector from the client and validated only its TYPE:
check(query, Match.OneOf(Object, null)). That is not validation, because a selector is executable data — $where makes the database run the caller's JavaScript once per document scanned (CWE-943 Improper Neutralization of Special Elements in Data Query Logic, CVSS 5.8)
- The surfaces: the
people, org, team and translation publications and their companion *CollectionCount / getPeoplePageIds methods. Meteor.subscribe('team', { $where: 'while(true){}' }, 25, 0) pins a database worker for as long as the caller likes and is repeatable — denial of service for every tenant on the instance. Demonstrated 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, which is 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
- 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; the eight siblings simply never called them. So the fix adds no new detection logic — that publication's own helper moved unchanged into server/lib/selectorGuard.js and all nine call sites share the one copy, because a second copy would be the same bug set up to happen again. Each refuses with the "match nothing" selector the card window already used in production, so a refused request returns an empty result rather than throwing at an admin mid-page, and ordinary searches, filters and paging are unaffected
- 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
- Fixed at upcoming WeKan release
- More details
|
GHSA-4mxf-m8pq-xc9p
|
|
PathBleed |
2026-08-09 |
Alpastx and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-4mxf-m8pq-xc9p.
|
Details
- PathBleed — an avatar's owner could write the ON-DISK PATH of their own avatar. Attachments refused client-supplied
versions.*.path; avatars did not, because that guard was written inside the attachment permission file and never copied. The whole avatar update rule was update: isOwner, which says WHOSE document may change and nothing about WHICH FIELDS (CWE-22 Path Traversal, CWE-73 External Control of File Name or Path)
- Board export then read it: for every member whose avatar is a local WeKan file the exporter opens
versions.original.path and embeds the bytes as base64 in profile.avatarFile. Point your own avatar at /etc/passwd — or anything under WRITABLE_PATH — export a board you are a member of, decode the JSON: arbitrary file read as the WeKan OS user, from any account that can own an avatar. The CDN download path was separately guarded; export was not
- Fixed at both ends. The WRITE: the three guards now live in
models/lib/fileVersionFields.js and BOTH permission files import them, so avatars refuse a versions payload on insert, refuse any update touching the versions subtree, and keep to the same field whitelist — ownership still required, no longer sufficient. The READ: nothing is read from a stored path unless it RESOLVES inside WeKan's own storage (models/lib/storagePathContainment.js), which also holds for a path poisoned by an old document, a restored backup or a bad migration. The download path's private copy of that check is gone, so download and export ask the same question
- Fixed at upcoming WeKan release
- More details
|
GHSA-jvv9-498p-hxrg
|
|
ParentBleed |
2026-08-09 |
Alpastx and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-jvv9-498p-hxrg.
|
Details
- ParentBleed — a card's
parentId may name a card on ANOTHER board, and setting it was authorized only against the CHILD board's write access. Nothing asked whether the person setting it, or the people subscribed to the child board, were allowed to see the other board (CWE-862 Missing Authorization)
- The board publication walks the whole ancestor chain, because the prefix-with-full-path subtask setting renders a subtask's complete path, and it published the complete ancestor card DOCUMENTS to every subscriber of the child board. Write access on shared board B plus one card id from private board A therefore delivered A's card — title, description, custom fields — over DDP to people with no part in A (CWE-200 Exposure of Sensitive Information)
- Fixed at both ends. The WRITE refuses a parent whose board the actor cannot see, asked in one place with the same selectors the publication and All Boards use — so an ACTIVE org/team/domain share counts and a revoked one does not — enforced on REST create, REST update and a DDP deny rule covering insert as well as update. The PUBLICATION sends only the ancestors whose board the subscriber may see; the board being published is its own answer, so an ordinary same-board subtask path is unchanged. It is the read check the linked-card path already made, applied to the field that lacked it
- Fixed at upcoming WeKan release
- More details
|
GHSA-gwc4-fw7p-gw58
|
|
RevokeBleed |
2026-08-09 |
Alpastx and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-gwc4-fw7p-gw58.
|
Details
- RevokeBleed —
isActive: false is how a board admin REVOKES a share with an organization, a team or an email domain, and the board publication never looked at it. All Boards asked correctly, with $elemMatch; the publication had its own copy written as 'orgs.orgId': { $in: [...] }, and a dotted path matches an array element without saying anything about that element's other fields (CWE-639 Authorization Bypass Through User-Controlled Key, CWE-863 Incorrect Authorization)
- So the board vanished from the revoked user's All Boards — which is what the admin saw and believed — while a subscription by a boardId they still remembered returned the whole private board: document, lists, swimlanes, cards, comments, attachments. A revoke the primary data publication does not honour is not a revoke. The same applied to team and domain shares
- Fixed by writing the rule once:
models/lib/boardVisibilitySelectors.js builds the $or, both Boards.userBoards and the board publication call it, and every share kind is matched with $elemMatch requiring isActive: true. The one clause that is not a relationship to the user — { permission: 'public' } — stays optional, so the boards list still shows public boards and the search over all boards still excludes them
- Fixed at upcoming WeKan release
- More details
|
GHSA-pqr4-rxgp-hv2m
|
|
CommentBleed |
2026-08-09 |
Alpastx and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-pqr4-rxgp-hv2m.
|
Details
- CommentBleed —
DELETE /api/boards/:boardId/cards/:cardId/comments/:commentId checked board MEMBERSHIP only, so any normal member could delete any other user's comment on the board (CWE-639 Authorization Bypass Through User-Controlled Key, CWE-863 Incorrect Authorization)
- The author-or-admin rule, and the board's
restrictCommentEditing setting, were enforced in a collection hook that decides from the Meteor userId — with an early return for the genuine server-internal callers (board copy, cleanup, migrations) that run with no user. An HTTP request is not one of those, but carries no Meteor userId either, so the removal landed on that trusted path: HTTP 200, somebody else's comment gone, on a restricted board, while the same deletion over DDP was correctly refused
- Fixed by asking the question where the answer is known: the handler loads the comment (404 when there is none) and applies the same rule itself, with
req.userId, before removing anything, answering 403 when it says no. That rule is now an exported function the hooks and the handler both call, so DDP and HTTP cannot enforce different things. The no-userId path stays, documented for the internal callers it was written for
- Fixed at upcoming WeKan release
- More details
|
-
|
|
PatternBleed |
2026-08-08 |
GitHub CodeQL (code scanning alert #431) and xet7
|
 
|
Process
Automated code scanning flagged the identity (no-op) replacement.
|
Details
- PatternBleed — an escape that escaped nothing. A platform name was interpolated into a regular expression through
p.replace('-', '-'), which replaces a hyphen with a hyphen: it reads as “escape this before putting it in a pattern” and does nothing at all, so the value went in raw (CWE-116 Improper Encoding or Escaping of Output)
- GitHub CodeQL code scanning alert #431, rule
js/identity-replacement, severity Medium
- Nothing failed, because a hyphen outside a character class needs no escaping — but the guard it looked like was not there, and a platform name carrying a
. or a + would have matched the wrong row or thrown. Test-only code (tests/releaseNodeSources.test.cjs) over a hardcoded list, so no runtime exposure
- Fixed by escaping the value for real, with the same
escapeRegExp the other guards in tests/ use. Being the SECOND finding of this rule after IdentityBleed (alert #424), the fix also adds tests/noIdentityReplacement.test.cjs, which catches the whole class in WeKan's own test run rather than after a push
- Fixed at upcoming WeKan release
- More details
|
GHSA-2g94-9x3m-hv37
|
|
LockoutBleed |
2026-08-04 |
NinjaGPT and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-2g94-9x3m-hv37.
|
Details
- LockoutBleed — user enumeration chained with unthrottled password brute-force into account takeover. The bundled
wekan-accounts-lockout (default 3 failures → 60 s lockout) was completely inert: its two Accounts.validateLoginAttempt hooks decided whether an attempt failed by comparing the error's REASON STRING (reason !== 'Incorrect password' for a known user, !== 'User not found' for an unknown one), but Meteor's ambiguousErrorMessages (on by default) rewrites every credential failure to one generic sentence BEFORE those hooks run. The literals never matched, both hooks returned early, the counter never incremented, and no account ever locked — unlimited unthrottled guessing (CWE-307 Improper Restriction of Excessive Authentication Attempts)
- The same login path leaked WHICH ACCOUNTS EXIST by timing: accounts-password runs a bcrypt comparison (~50 ms) only for a user that exists and has a local password, and returns in ~2 ms otherwise. The distributions do not overlap, so an unauthenticated attacker classifies any username or email as real or not with near-100% accuracy, regardless of the uniform error text (CWE-208 Observable Timing Discrepancy / CWE-204). The REST
POST /users/login twin was worse: it threw a distinct “User with that username or email address not found.” for a missing user and never went through the lockout hooks at all
- Fixed by deciding lockout from the attempt's STRUCTURAL fields instead of a localized Meteor-internal string (new
packages/wekan-accounts-lockout/src/loginFailureDecision.js), so any genuine password failure is counted and the lockout fires — while the benign no-2fa-code step (password already correct, second factor still to come) is never counted, so 2FA users are not locked out of their own sign-in
- The enumeration timing is equalised with one DUMMY BCRYPT COMPARISON against a fixed cost-10 hash whenever the real path would skip bcrypt (
server/lib/loginTimingDefense.js), wired into the DDP login method by a normalization handler that runs ahead of the built-in one and never authenticates (server/loginTimingNormalization.js). The REST endpoint now answers missing-user and wrong-password IDENTICALLY, runs the same equaliser, and THROTTLES failed attempts per client address (server/lib/loginAttemptThrottle.js) — only failures count and a success clears the counter
- Fixed at upcoming WeKan release
- More details
|
GHSA-j9p2-jm73-p549
|
|
FollowBleed |
2026-08-03 |
RandomGenerator and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-j9p2-jm73-p549.
|
Details
- FollowBleed — a redirect walked the import downloads past the SSRF guard. The live Trello import (
server/trelloApiImport.js) DID validate the attachment URL with validateAttachmentUrl() — the fix that closed LiveBleed / CVE-2026-30844 — and then downloaded it with the platform fetch(), which FOLLOWS REDIRECTS. So the guard only ever saw the request, and the target gets to answer: a public URL passes validation, that host replies 302 Location: http://127.0.0.1:18080/secret, and the loopback response body is stored as the imported attachment and read back through WeKan. Non-blind SSRF against loopback services, internal admin panels, cloud metadata and anything else reachable from the container (CWE-918 Server-Side Request Forgery)
- A guard on the URL alone cannot hold, because the target gets to answer and an answer can name a new URL.
fetchSafe() (server/lib/ssrfGuard.js) now guards EVERY HOP: maxRedirects defaults to 0, which refuses any 3xx outright as before — right for outgoing webhooks and avatar downloads, because a legitimate one never redirects — and a caller that must follow one passes a small number, each hop going through the same protocol allowlist, blocked-range check and DNS pinning as the original URL before a packet is sent to it. Credentials are dropped on a cross-origin redirect, so following Trello's 302 to S3 cannot hand the API key and token to whoever the redirect names
- Refusing every redirect was not an option: Trello's own attachment endpoint answers with a 302 to a signed S3 URL, so that would have meant importing no attachments at all
- The OFFLINE importers had the same hole and were not in the report: they handed the validated URL to Meteor-Files'
Attachments.loadAsync(), which downloads with the platform fetch() too, so a pasted Trello or WeKan board export reached 127.0.0.1 by exactly the same 302. They download through the guard now
- Fixed at upcoming WeKan release
- More details
|
GHSA-c5xr-mg26-vq5w
|
|
TransitBleed |
2026-08-03 |
tonghuaroot and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-c5xr-mg26-vq5w.
|
Details
- TransitBleed — IPv6 transition addresses walked straight through the SSRF block-list.
isIpBlocked() in models/lib/attachmentUrlValidation.js is the ONE block-list behind both halves of the defence — the input-time validator and the delivery-time guard fetchSafe() — and its IPv6 half classified an address by its SPELLING: startsWith('::ffff:'), startsWith('2001:db8'), and the first hextet parsed out of the string. IPv6 has several standard ways to write “this packet goes to an IPv4 address” and none of them looks like ::ffff: (CWE-918 Server-Side Request Forgery)
- The forms that passed:
2002:a9fe:a9fe:: — 6to4 (RFC 3056) → 169.254.169.254; 64:ff9b::c0a8:101 — NAT64 (RFC 6052) → 192.168.1.1; 2001:0:… — Teredo (RFC 4380), the IPv4 stored as the complement of the low 32 bits; and even 0:0:0:0:0:ffff:7f00:1, a plain IPv4-mapped 127.0.0.1 merely spelled out. On a host with a 6to4 relay or a NAT64 gateway — ordinary in cloud and Kubernetes networks — the packet arrives at that IPv4 address, so http://[2002:a9fe:a9fe::]/latest/meta-data/ read cloud metadata through the guard whose whole job was to stop it
- Fixed by EXPANDING the address to its 16 bytes once and reading those bytes, so notation cannot change the answer, and extracting the embedded IPv4 from every transition form to re-check it with the IPv4 rules: 6to4, NAT64 (the well-known prefix and the RFC 8215 local-use one), Teredo through both its server and its obfuscated client address, IPv4-mapped, IPv4-translated, IPv4-compatible, and ISATAP under any routing prefix rather than only the link-local one. The deprecated
fec0::/10 site-local range is blocked too
- A transition address wrapping a PUBLIC IPv4 is still allowed, and the tests pin that as carefully as they pin the bypasses: a guard that blocks everything is a guard somebody switches off
- Fixed at upcoming WeKan release
- More details
|
CVE-2026-68901 GHSA-3gcg-g6rf-w2rx
|
|
CrashBleed |
2026-07-26 |
laijunyue and xet7
|
   
|
Process
Coordinated disclosure via GitHub Security Advisory GHSA-3gcg-g6rf-w2rx.
|
Details
- CrashBleed — remote denial of service: an invalid
authToken on a board export endpoint crashed the whole server. The board export REST endpoints look a user up by the login token in ?authToken=. A token that matches nothing makes that lookup answer undefined, and the next line dereferenced it — user._id.toString() — throwing a TypeError out of an async route handler with no try/catch. That escapes as an unhandled promise rejection, which this app turns into a full process crash, so one crafted GET against a private board id took the server down for every user. Reachable by anyone who can obtain a private board id, which on an open-registration instance means anyone at all (CVE-2026-68901 GHSA-3gcg-g6rf-w2rx, CWE-476)
- It was an incomplete fix:
models/exportPDF.js and models/exportExcelCard.js already had the if (!user) guard; three handlers in models/export.js and one in models/exportExcel.js were missed
- Fixed on both levels: every token lookup in the export models is now followed by that guard — 401 “Invalid token” and return — including the two handlers that did not crash because they hand the user to
canExport() instead of dereferencing it; and every export route body is wrapped in safeRoute() (server/apiMiddleware.js), which awaits the handler, answers 500 once and logs the request that failed, so a throw from any other cause is one broken request instead of an outage
- Affected Wekan v10.37 and earlier; fixed at Wekan v10.38 2026-07-26
- More details
|
-
|
|
ZipBleed |
2026-07-25 |
xet7
|
 
|
Process
Found while reviewing the open dependency pull requests.
|
Details
- ZipBleed — restoring a backup archive wrote entries wherever the archive told it to. A zip entry carries its own path and
path.join() RESOLVES .. segments instead of rejecting them, and the restore in server/methods/backup.js checked only that an entry's first path segment was attachments or avatars. An entry named 2026-07-25_12-00-00/attachments/../../../../etc/cron.d/wekan passed that check — its first segment really is attachments — and joined its way out of the files directory, so a crafted backup.zip could drop or overwrite a file anywhere the WeKan process could write (CWE-22 Improper Limitation of a Pathname to a Restricted Directory, "zip-slip")
- Reachable by an admin restoring an archive (
restoreBackup is behind requireAdmin()), which is how a hostile archive arrives: offered as a backup to restore, at the moment nobody inspects the file they were handed
- Fixed by resolving each entry to an absolute path and requiring it to sit under the directory it belongs in, compared against the base plus a separator so a sibling directory with a matching prefix (
/data/files/attachments-evil) is refused too; the collection name in the data half of an archive is constrained to a plain name, which also keeps a restore out of the database's internal system.* collections
- Fixed at upcoming WeKan release
- More details
|
CVE-2026-68900 GHSA-8r5p-4q9j-f5jx
|
|
ExportBleed |
2026-07-22 |
koyokr and xet7
|
   
|
Process
Privately reported via GitHub Security Advisory GHSA-8r5p-4q9j-f5jx.
|
Details
- ExportBleed — a board member could store entity-encoded markup in a card title (e.g.
<img src=x onerror=…>). It stays inert on the live board, but the HTML board exporter (client/lib/exportHTML.js) embedded a card-click handler that read the title/body via .textContent (which DECODES entities) and concatenated them into innerHTML. That second parse revived the tag and ran it when a recipient clicked the card in the export, disclosing all data in that document, including cards added AFTER the attacker's board membership was revoked. Fixed by building the modal from DOM nodes and assigning the title/body via textContent, never innerHTML (CWE-79 Cross-site Scripting)
- Reported privately by koyokr (https://github.com/koyokr) via GHSA-8r5p-4q9j-f5jx
- Fixed at upcoming WeKan release
- More details
|
-
|
|
RedirectBleed |
2026-07-19 |
meifukun and xet7
|

|
Process
Privately reported 8 issues reviewed against WeKan v9.95.0.
|
Details
- RedirectBleed — avatar localization (
server/lib/localizeAvatar.js) validated only the ORIGINAL URL host with assertSafePublicUrl and then fetched with native fetch(url, {redirect:'follow'}), so an authenticated user could set profile.avatarUrl to a public redirector that 302s to 127.0.0.1, a private network, or 169.254.169.254 and the WeKan server followed it (SSRF). Fixed by fetching through the DNS-pinned, redirect-rejecting fetchSafe and scheme-validating profile.avatarUrl at write time (CWE-918 Server-Side Request Forgery)
- Reported privately by meifukun (https://github.com/meifukun)
- Fixed at upcoming WeKan release
- More details
|
-
|
|
SourceBleed |
2026-07-19 |
meifukun and xet7
|

|
Process
Privately reported 8 issues reviewed against WeKan v9.95.0.
|
Details
- SourceBleed — a Trello board imported with a
javascript: url had that URL stored as an activity source.url (models/trelloCreator.js) and rendered as an activity-sidebar link (client/components/activities/activities.js) with no scheme check, so a board admin who clicked the "Trello" source link ran attacker JavaScript in their session and could read Meteor.loginToken (stored XSS → account takeover). Fixed by only storing and linking http(s) source URLs (CWE-79 Stored Cross-site Scripting)
- Reported privately by meifukun (https://github.com/meifukun)
- Fixed at upcoming WeKan release
- More details
|
-
|
|
LiveBleed |
2026-07-19 |
meifukun and xet7
|

|
Process
Privately reported 8 issues reviewed against WeKan v9.95.0.
|
Details
- LiveBleed — the live Trello import (
server/trelloApiImport.js) downloaded attacker-controlled Trello attachment / background / avatar URLs with bare fetch() — no SSRF guard, unlike the offline path — and stored the response as an imported attachment readable back through the attachment API, giving NON-BLIND SSRF (cloud metadata / internal services). Fixed by gating every live-import download with validateAttachmentUrl(), matching the offline import (CWE-918 Server-Side Request Forgery)
- Reported privately by meifukun (https://github.com/meifukun)
- Fixed at upcoming WeKan release
- More details
|
-
|
|
CasRaceBleed |
2026-07-19 |
meifukun and xet7
|

|
Process
Privately reported 8 issues reviewed against WeKan v9.95.0.
|
Details
- CasRaceBleed — with CAS login enabled,
packages/wekan-accounts-cas/cas_server.js stored validated CAS user data in a single module-global _userData shared across concurrent logins. Two logins racing could bind an attacker's credential token to a victim's user data, issuing the attacker a session for the victim's account (full admin if the victim was an admin). Fixed by binding the validated CAS user data PER credential token (CWE-362 Race Condition → Account Takeover)
- Reported privately by meifukun (https://github.com/meifukun)
- Fixed at upcoming WeKan release
- More details
|
-
|
|
MetricsBleed |
2026-07-19 |
meifukun and xet7
|

|
Process
Privately reported 8 issues reviewed against WeKan v9.95.0.
|
Details
- MetricsBleed — the
/metrics endpoint (models/server/metrics.js) trusted the client-supplied X-Forwarded-For header UNCONDITIONALLY when checking METRICS_ACCEPTED_IP_ADDRESS, so an unauthenticated requester could send X-Forwarded-For: <whitelisted-ip> and read operational Prometheus metrics (connected/registered user counts, board counts, active board titles). Fixed by trusting XFF only when METRICS_TRUST_PROXY is set (parsed spoof-resistantly from the right); otherwise the real socket peer address is used (CWE-290 Authentication Bypass by Spoofing)
- Reported privately by meifukun (https://github.com/meifukun)
- Fixed at upcoming WeKan release
- More details
|
-
|
|
ImpersonateBleed |
2026-07-19 |
meifukun and xet7
|

|
Process
Privately reported 8 issues reviewed against WeKan v9.95.0.
|
Details
- ImpersonateBleed — several board export endpoints (
models/export.js, exportExcel.js, exportExcelCard.js, exportPDF.js) authorized export with canExport(user) || impersonateDone, where impersonateDone was merely the existence of ANY historical ImpersonatedUsers record for the user. A former admin who ever used impersonation kept permanent export access to any private board even after being demoted. Fixed by removing the impersonation bypass so export requires real board visibility (canExport) only (CWE-863 Incorrect Authorization)
- Reported privately by meifukun (https://github.com/meifukun)
- Fixed at upcoming WeKan release
- More details
|
-
|
|
InviteBleed |
2026-07-19 |
meifukun and xet7
|

|
Process
Privately reported 8 issues reviewed against WeKan v9.95.0.
|
Details
- InviteBleed — when public registration is disabled, invitation registration used a 6-digit code generated with
Math.random() (~900,000 keyspace, non-cryptographic RNG; server/models/settings.js) with no throttling on the sign-up validation, so an attacker who knew a pending invitee's email could brute-force the code, claim the account and join its private boards. Fixed by generating a 128-bit crypto.randomBytes invitation code and rate-limiting createUser with DDPRateLimiter (CWE-330 Insufficiently Random Values + CWE-307 Excessive Auth Attempts)
- Reported privately by meifukun (https://github.com/meifukun)
- Fixed at upcoming WeKan release
- More details
|
-
|
|
SpliceBleed |
2026-07-22 |
GitHub CodeQL (code scanning alert #425) and xet7
|
 
|
Process
Automated code scanning flagged the incomplete multi-character sanitization.
|
Details
- SpliceBleed —
stripExploitPatterns() in imports/lib/fileNameDisplay.js removed HTML/script/XML/template markup from a shown filename in a single pass, so an input with nested or interleaved fragments (for example <scr<x>ipt> or <scr{{y}}ipt>) could have its inner part removed and the two surviving outer fragments spliced together into a fresh <script> token the single pass no longer re-examined (CWE-116 Improper Encoding or Escaping of Output)
- GitHub CodeQL code scanning alert #425, rule
js/incomplete-multi-character-sanitization, severity High
- Fixed by applying the removals repeatedly until the string stops changing (a fixpoint loop); each pass only deletes text, so the string strictly shrinks and always terminates, and any dangerous token an earlier removal reveals is then removed too. Blaze
{{ }} already HTML-escapes every rendered filename, so this is defence-in-depth on the displayed text rather than a live XSS, but the single-pass strip was genuinely incomplete
- Fixed at upcoming WeKan release
- More details
|
-
|
|
IdentityBleed |
2026-07-22 |
GitHub CodeQL (code scanning alert #424) and xet7
|
 
|
Process
Automated code scanning flagged the identity (no-op) replacement.
|
Details
- IdentityBleed — a test in
tests/securityLog.test.cjs built a menu-id regex with id.replace('report-', 'report-'), replacing a substring with itself: a no-op that CodeQL flags because it is almost always a mistake for a real transformation (CWE-116 Improper Encoding or Escaping of Output)
- GitHub CodeQL code scanning alert #424, rule
js/identity-replacement, severity Medium
- Fixed by dropping the dead
replace and matching 'js-' + id directly. Test-only code with no runtime exposure, but the no-op was removed for correctness
- Fixed at upcoming WeKan release
- More details
|
-
|
|
EscapeBleed |
2026-07-17 |
GitHub CodeQL (code scanning alert #423) and xet7
|
 
|
Process
Automated code scanning flagged the incomplete escaping.
|
Details
- EscapeBleed — code that built a
RegExp from a CSS declaration in tests/maximizedCardPosition.test.cjs escaped only parentheses (str.replace(/[()]/g, '\\$&')) instead of the full regex metacharacter set, so an input containing other metacharacters (including a backslash) would not be escaped correctly and the generated pattern could match the wrong thing (CWE-116 Improper Encoding or Escaping of Output)
- GitHub CodeQL code scanning alert #423, rule
js/incomplete-sanitization, severity High
- Fixed by escaping the complete metacharacter set (
str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')), matching the correct pattern already used elsewhere in the tests. Test-only code with a fixed, trusted input list — no injection exposure — but the incomplete escape was genuinely wrong
- Fixed at upcoming WeKan release
- More details
|
-
|
|
RandomBleed |
2026-07-17 |
GitHub CodeQL (code scanning alert #422) and xet7
|
 
|
Process
Automated code scanning flagged the biased randomness.
|
Details
- RandomBleed — the startup schema upgrade (
server/lib/schemaUpgradeSteps.js) generates Meteor-style document ids with crypto.randomBytes(len) mapped through byte % ID_CHARS.length. Because 256 is not a multiple of the 55-character alphabet, that modulo skews generated ids toward the first 36 characters (each ~1.4% more likely than the rest), reducing the entropy of the ids used for the swimlanes/lists/checklist-items the upgrade creates (CWE-1204 weak randomness)
- GitHub CodeQL code scanning alert #422, rule
js/biased-cryptographic-random, severity High
- Fixed with rejection sampling: bytes at or above the largest multiple of the alphabet size (220) are discarded and resampled, so every character is exactly equally likely; ids stay Meteor-style 17 characters. A negative regression test pins that out-of-range bytes are never wrapped
- Fixed at upcoming WeKan release
- More details
|
CVE-2026-68899 GHSA-jhph-whx8-wq6p
|
|
MimeBleed |
2026-07-14 |
HNUfwj (coordinated disclosure) and xet7
|
  
|
Process
Did send detailed report with PoC!
|
Details
- MimeBleed — file-upload MIME-type validation bypass leading to stored XSS (CVE-2026-68899 GHSA-jhph-whx8-wq6p, CWE-434). WeKan's upload validation (
models/fileValidation.js) detects a file's real MIME type by running the Unix file command. On minimal Docker/Alpine images where file is not installed, detectMimeFromFile() silently returned undefined and the code fell back to the CLIENT-supplied fileObj.type. An authenticated board member (with WITH_API=true) could upload an HTML file containing JavaScript while setting fileType: "image/png": the spoofed type is not on the dangerous-MIME deny-list, so the dangerous-content scan was skipped and the file was stored, giving stored XSS served under the WeKan origin (session theft, actions as the victim, including admin)
- CVSS:3.1 8.3 High (AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N)
- Fixed so the client-supplied type can never gate the safety scan: when content-based detection via
file is unavailable, WeKan falls back to a dependency-free JS content sniff (looksLikeDangerousMarkup()) that inspects the real bytes for HTML/SVG/XML/<script> signatures and forces the dangerous-content scan regardless of the claimed MIME, so a spoofed image/png that is really HTML+JS is rejected. The sniff only matches definitive markup, so genuine binary uploads (real PNG/JPEG/PDF, including large ones) are unaffected. WeKan also logs a one-time warning when file is missing (previously silent)
- Affected container deployments without the
file binary and WITH_API=true; fixed at the upcoming WeKan release
- More details
|
CVE-2026-68561 GHSA-xm8x-c8wg-jhmf
|
|
SortBleed |
2026-07-13 |
5ud0 / Tarmo Technologies (coordinated disclosure) and xet7
|
   
|
Process
Did send detailed report with PoC!
|
Details
- SortBleed — broken access control / privilege escalation: a low-privilege (comment-only / read-only) board member could escalate to board admin and take over a private board via the board
sort collection-allow rule (CVE-2026-68561 GHSA-xm8x-c8wg-jhmf, CWE-863, CWE-269). To support drag-to-reorder, a second Boards.allow({ update }) rule returned true for any board member whenever the update touched the sort field. Meteor evaluates allow rules with OR semantics and does not scope an approving rule to the field that satisfied it: once any allow callback approves and no deny rejects, the ENTIRE modifier is applied. Because canUpdateBoardSort only checked that sort was AMONG the modified fields (not the only one), a comment-only / read-only member could smuggle arbitrary board mutations into the same $set as sort in one DDP Boards.update call — {$set: {sort: 99, members: [...self as admin...], permission: 'public', title: '...'}} — making themselves admin, flipping the private board to public, renaming it, and evicting the legitimate owner. The last-admin deny rule did not help because it only inspected $pull. Same allow-rule field-conflation class as BoardBleed (CVE-2026-55234), but on the Board document itself
- CVSS:3.1 8.8 High (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
- Fixed by restricting
canUpdateBoardSort (server/lib/utils.js) so the sort-reorder rule approves an update ONLY when sort is the sole modified field (fieldNames is exactly ['sort']). Defense in depth: the last-admin deny rule (server/permissions/boards.js) now also rejects a $set rewrite of the members array that would drop the last active admin. The legitimate All Boards drag-reorder is unaffected — it persists order per-user in profile.boardSortIndex, not in the board document
- Affected Wekan v9.85 and earlier through the current release; fixed at the upcoming WeKan release
- More details
|
CVE-2026-68560 GHSA-x3xm-pxrv-jg7p
|
|
ScannerBleed |
2026-07-05 |
DavidCarliez (coordinated disclosure) and xet7
|
   
|
Process
Did send detailed report with PoC!
|
Details
- ScannerBleed — shell injection (RCE) via a malicious upload filename in the external antivirus scanner command path. In
models/fileValidation.js, when an admin-configured external scanner command line with a {file} placeholder is set, the uploaded file path was interpolated and run through asyncExec (promisify(exec)), which spawns /bin/sh -c and interprets all shell metacharacters. Wrapping the path in double quotes is not a shell boundary — inside double quotes the shell still expands $(...), backticks and \ — so a filename like $(touch /tmp/pwn).png or a`id`.png executed as the Wekan server process. Any authenticated user who can upload an attachment could trigger it. Same RCE class as AvatarBleed (CVE-2026-52891), but in a code path that was never covered by that fix (CVE-2026-68560 GHSA-x3xm-pxrv-jg7p, CWE-78)
- CVSS:3.1 9.9 Critical (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H)
- Unlike the sibling MIME-detection path (
detectMimeFromFile, which already uses execFile with no shell) and unlike the AvatarBleed fix (which strips non-alphanumeric characters), this scanner path had zero sanitization. Fixed by POSIX single-quote-escaping the interpolated file path via a new shellQuote() helper — inside single quotes the shell interprets no metacharacters, so a malicious filename can no longer inject commands, while the admin's command line and the exact on-disk path are preserved
- Affected Wekan v9.06 and earlier through the current release; fixed at the upcoming WeKan release
- More details
|
CVE-2026-68559 GHSA-mwq8-ccpm-r533
|
|
ExcelBleed |
2026-07-05 |
sec-reex (coordinated disclosure) and xet7
|
   
|
Process
Did send detailed report with runtime-confirmed PoC!
|
Details
- ExcelBleed — broken access control in the Excel-export route (
GET /api/boards/:boardId/exportExcel): models/exportExcel.js called its guard exporterExcel.canExport(user) without await. Because canExport is async it returns an always-truthy Promise, so if (exporterExcel.canExport(user) || impersonateDone) was always true and the export ran regardless of the guard's real result. Any authenticated user could download the full contents of any private board they are not a member of (card titles + descriptions, lists, swimlanes, members, metadata). Same un-awaited async-auth bug class as BFLABleed, CloneBleed and TokenBleed (CVE-2026-68559 GHSA-mwq8-ccpm-r533, CWE-862, CWE-639)
- CVSS:3.1 Moderate (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N)
- The Excel-export route was the lone remaining un-awaited
canExport call site; the JSON export route (/export) was correctly awaited and returned 403 to the same non-member. Fixed by adding await, matching every other export route (export.js, exportPDF.js, exportExcelCard.js, import.js)
- Affected Wekan v9.57.0 and earlier; fixed at the upcoming WeKan release
- More details
|
CVE-2026-68558 GHSA-66m2-4wfr-c45p
|
|
DnsBleed |
2026-07-01 |
4n207 (coordinated disclosure) and xet7
|
   
|
Process
Did send detailed report with PoC!
|
Details
- DnsBleed — the synchronous outgoing-webhook (board Integrations) URL validator in
models/integrations.js blocks private/loopback/link-local IPs by regex-matching the URL hostname string and never resolves DNS, so a public hostname that resolves to a blocked address (e.g. 169-254-169-254.nip.io → 169.254.169.254, or any attacker A/AAAA record → internal IP) passes the blocklist. Incomplete-fix follow-up to WebhookBleed / IntegrationBleed RebindBleed (CVE-2026-68558 GHSA-66m2-4wfr-c45p, CWE-918)
- CVSS:3.1 High (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N)
- The reported PoC was already blocked at delivery by the RebindBleed
fetchSafe guard and at REST input by validateAttachmentUrl(); this release completes the fix by making fetchSafe resolve both address families and validate through the single shared isIpBlocked block-list, removing the block-list drift the advisory points at
- Affected Wekan v8.36 and later; fixed at the upcoming WeKan release
- More details
|
CVE-2026-59154 GHSA-gv8h-5p3p-6hx7
|
|
ChecklistBleed |
2026-06-20 |
DavidCarliez (coordinated disclosure) and xet7
|
   
|
Process
Did send detailed report with PoC!
|
Details
- ChecklistBleed — the Checklists/ChecklistItems DDP collection allow rules (
server/permissions/checklists.js, checklistItems.js) authorized an update against only the document's CURRENT (source) cardId, never the destination. A low-privileged user could move a checklist/item they own onto a card in a private board they are not a member of by $set-ting a new cardId/checklistId (boardId is then denormalized from the destination card), writing attacker-controlled checklist data into the victim's private board — same class as BoardBleed, but for the card-attached checklist documents (CVE-2026-59154 GHSA-gv8h-5p3p-6hx7, CWE-863)
- CVSS:3.1 Moderate (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N)
- Fixed by adding
denyCrossBoardMoveByCard/denyCrossBoardMoveByChecklistItem in server/lib/utils.js and a Checklists.deny/ChecklistItems.deny update rule that rejects any move whose destination board the caller cannot write to
- Affected Wekan v9.62 and earlier; fixed at the upcoming WeKan release
- More details
|
-
|
|
InputBleed |
2026-06-18 |
GitHub CodeQL (code scanning alert #421) and xet7
|
 
|
Process
Automated code scanning flagged the incomplete sanitization.
|
Details
- InputBleed —
stripHtml() in client/lib/importDependencies.js stripped HTML tags with a single pass of /<[^>]*>/g. That is incomplete: a dangling unclosed tag with no closing > (e.g. a trailing <script or <svg/onload=...) is never matched by the regex and survives untouched, leaving <script in the output; and removing one match can splice surrounding text into a new match. A crafted card-dependency ("Red Strings") import file could thus smuggle an HTML/script fragment past the sanitizer (CWE-79, CWE-80, CWE-116)
- GitHub CodeQL code scanning alert #421, rule
js/incomplete-multi-character-sanitization, severity High
- Fixed by looping the tag-stripping replacement to a fixed point and then removing any remaining stray
</> characters, so neither a complete nor a partial tag can remain
- Fixed at Wekan v9.52 2026-06-18
- More details
|
GHSA-jggc-qvfc-jr6x
CVE requested
|
|
ProxyBleed |
2026-06-15 |
rz1027 (coordinated disclosure) and xet7
|
   
|
Process
Did send detailed report with PoC!
|
Details
- 1. ProxyBleed — header-login IP allowlist bypass via X-Forwarded-For spoofing (GHSA-jggc-qvfc-jr6x, CWE-290, CWE-287, CWE-348). Wekan's header-login (reverse-proxy SSO) feature gated passwordless login on a source-IP allowlist (
HEADER_LOGIN_TRUSTED_IPS) but read the client-supplied X-Forwarded-For header as the source IP. An unauthenticated attacker who can reach the app port directly sends a single GET request with a spoofed X-Forwarded-For: <allowlisted-ip> plus the username header (e.g. X-Auth-User: admin) and is minted a full passwordless login session (meteor_login_token) for any existing user including admin — complete account takeover and admin impersonation. An empty allowlist also failed open
- CVSS: 9.8 Critical (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
- The fix derives the source IP from the real TCP socket peer, only honors
X-Forwarded-For when the immediate peer is a configured trusted proxy (taking the right-most untrusted hop), and fails closed when the allowlist is unset
- Affected Wekan v9.44 and earlier
- Fixed at See CHANGELOG (v9.46)
- More details
|
CVE-2026-55234 GHSA-gm7v-pc38-53jr
|
|
BoardBleed |
2026-06-11 |
0xzap (coordinated disclosure) and xet7
|
  
|
Process
Did send detailed report with PoC!
|
Details
- 1. BoardBleed — broken access control: any authenticated user could move their Cards/Lists/Swimlanes into a private board they are not a member of (cross-board write via collection allow rule) (CVE-2026-55234 GHSA-gm7v-pc38-53jr, CWE-284, CWE-639). The DDP write policies for Cards, Lists and Swimlanes authorized an update by checking only the document's CURRENT (source)
boardId and never validated the NEW boardId in the update modifier; any logged-in user could $set boardId to a victim's private board over /cards/update, /lists/update or /swimlanes/update and inject attacker-controlled cards/lists/swimlanes into a board they cannot even read
- CVSS: 7.x High (AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L)
- The REST move endpoint (
PUT /api/boards/:boardId/lists/:listId/cards/:cardId with newBoardId) was not affected; it checks checkBoardWriteAccess on the destination board. Only the DDP allow/deny layer was vulnerable
- Affected Wekan v9.35 and earlier
- Fixed at See CHANGELOG (v9.37)
- More details
|
CVE requested
|
|
TokenBleed |
2026-06-10 |
Zion Boggan (coordinated disclosure) and xet7
|
   
|
Process
Did send detailed report with PoC!
|
Details
- 1. TokenBleed — unauthenticated login-token minting via un-awaited auth check in
POST /api/createtoken/:userId (CWE-863, CWE-287). Authentication.checkUserId is async, so its 401/403 throws became rejected promises that a synchronous try/catch could not catch; the un-awaited call never stopped execution, so the handler minted and returned a usable login token for any user ID — including an admin — with no credentials (unauthenticated account takeover)
- 2. The same detached-rejection bypass affected the other un-awaited
checkUserId/checkAdminOrCondition handlers: GET /api/users, GET /api/users/:userId, PUT /api/users/:userId, POST /api/users/, DELETE /api/users/:userId, POST /api/deletetoken, GET /api/boards, GET /api/boards_count, DELETE /api/boards/:boardId, GET /api/users/:userId/boards and POST /api/boards/:boardId/copy (user enumeration, deletion, takeOwnership, board member changes and board deletion)
- Affected Wekan v9.35 and earlier
- Fixed at See CHANGELOG (v9.36)
- More details
|
CVE-2026-53447 GHSA-qfqv-42qw-vvwh
|
|
CloneBleed |
2026-06-04 |
dizconnectz (cloneBoard) and xet7 (similar issues found by code review)
|
   
|
Process
Did send detailed report with full PoC!
|
Details
- 1. TokenBleed —
cloneBoard Meteor method had no authorization check: any user could clone (read) any private board by ID (CWE-639, CWE-862)
- CVSS: 6.5 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N)
- 2. moveChecklist membership guard never ran (async helper unimported and un-awaited)
- 3. updateListSort guard referenced an unimported function, so it never ran
- 4. Attachment API methods/handlers called non-existent
isBoardMember; card/board relationship not verified
- 5. applyListWidth stored per-board list width with no board membership check
- 6. getBackgroundImageURL returned any board's background by ID
- 7. Missing-lists migration status/execute methods missing board authorization
- 8. Attachment migration methods missing board authorization
- 9. Outgoing webhook delivery trusted caller-supplied integration object
- 10. userPositionHistory checkpoint methods missing board visibility check (PositionHistoryBleed class)
- 11. Custom Field allow rules used membership not write-access — read-only members could write Custom Fields via DDP (ReadOnlyBleed class)
- 12. Comment-reaction allow rules let read-only members add/remove reactions
- 13. archiveBoard required only membership, not board admin (UI gates it behind admin)
- 14. sendSMTPTestEmail required only login, not global admin
- Affected Wekan v9.34 and earlier
- Fixed at See CHANGELOG (v9.35)
- More details
|
CVE-2026-53444 GHSA-cv95-8h7c-2ffq,
CVE-2026-52893 GHSA-mp7g-hj5q-gxhq
|
|
OIDCBleed |
2026-05-31 |
alexwaira (coordinated disclosure) and xet7
|
   
|
Process
Did send detailed report!
|
Details
- 1. Missing authorization on OIDC Meteor methods allows privilege escalation to admin (CVE-2026-53444 GHSA-cv95-8h7c-2ffq, CWE-269, CWE-862). Six OIDC-flow methods were globally DDP-callable;
groupRoutineOnLogin could set isAdmin from caller data
- 2. OIDC account takeover via unconditional email-based account merge in
Accounts.onCreateUser (CVE-2026-52893 GHSA-mp7g-hj5q-gxhq, CWE-287)
- Affected Wekan v9.31 and earlier
- Fixed at
Wekan v9.32 2026-05-31
- More details
|
CVE-2026-52892 GHSA-6733-4wgq-8xvr
|
|
ReadOnlyBleed |
2026-05-31 |
Wernerina (coordinated disclosure) and xet7
|
   
|
Process
Did send detailed report!
|
Details
- 1. Read-only board members could create/modify/delete Custom Fields (CVE-2026-52892 GHSA-6733-4wgq-8xvr, CWE-862). The six mutating Custom Field REST handlers used the read-level
checkBoardAccess instead of checkBoardWriteAccess
- Affected Wekan v9.31 and earlier
- Fixed at
Wekan v9.32 2026-05-31
- More details
|
CVE-2026-53446 GHSA-hc3x-hq3m-663q,
CVE-2026-53445 GHSA-7w2h-g83c-jqrp
|
|
WebhookBleed |
2026-05-31 |
xet7
|
  
|
Process
Found and fixed by code review.
|
Details
- 1. Server-Side Request Forgery (SSRF) via webhook integration URLs — input-side validation (CVE-2026-53446 GHSA-hc3x-hq3m-663q, CWE-918). Builds on the v8.35/v8.36 IntegrationBleed delivery-layer fix
- 2. Authorization bypass in
copyBoard DDP method allows any user to copy private boards (CVE-2026-53445 GHSA-7w2h-g83c-jqrp, CWE-862). Tightened to require board admin, matching the REST endpoint
- 3. Regression from the avatar RCE fix (CVE-2026-52891 GHSA-35j7-h385-2q9g): external antivirus scanner broken (
asyncExec undefined)
- Affected Wekan v9.31 and earlier
- Fixed at
Wekan v9.32 2026-05-31
- More details
|
CVE-2026-52890 GHSA-g6vm-7757-pr88
|
|
FilePathBleed |
2026-05-27 |
Jan Kahmen of turingpoint GmbH
|
  
|
Process
Reported responsibly, fixed quickly.
|
Details
- 1. Arbitrary file read and server DoS via attachment
versions.original.path (CVE-2026-52890 GHSA-g6vm-7757-pr88, CWE-22, CWE-400)
- Affected Wekan v9.30 and earlier
- Fixed at
Wekan v9.31 2026-05-27
- More details
|
-
|
|
BFLABleed |
2026-05-19 |
Fredrik Dietrichson
|
   
|
Process
Did send detailed report with full PoC and runtime verification!
|
Details
- 1. CloneBleed — Broken Function Level Authorization: 48 REST endpoints missing await on board access checks, allowing authenticated non-members to read/write any board.
- CVSS: 8.1 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N)
- Affected Wekan v9.20-v9.22
- Fixed at See CHANGELOG
- More details
|
-
|
|
AuthBleed |
2026-05-07 11:39 EET |
Qiulin Deng
|

|
Process
Did send detailed report with full PoC and runtime verification!
|
Details
- 1. AuthBleed
- 2. CopyCardBleed
- 3. CopyBoardBleed
- 4. CopyListBleed
- 5. DueDateBleed
- 6. CopySwimlaneBleed
- 7. MoveListBleed
- CVSS: 9.1 — Affected Wekan v9.08 and earlier
- Fixed at
Wekan v9.09 2026-05-07
- More details
|
-
|
|
AvatarBleed |
2026-05-03 13:57 EET |
Trung Nguyen from CyStack Security
|
   
|
Process
Did send detailed report and suggested fix!
|
Details
|
IntegrationBleed FileBleed CVE-2026-41455,
IntegrationBleed RebindBleed CVE-2026-41454
|
|
IntegrationBleed |
2026-02-24 15:09 EET |
Rodolphe GHIO
|
   
|
Process
Did send detailed report and fix!
|
Details
|
-
|
|
AnchorBleed |
2026-02-12 11:16 EET |
The GitHub Security Lab team
|
 
|
Process
Did send detailed report and fix!
|
Details
- 1. GHSL-2026-035_Wekan AnchorBleed
- 2. GHSL-2026-036_Wekan WatchBleed
- 3. GHSL-2026-037_Wekan GlobalBleed
- 4. GHSL-2026-044_Wekan CustomFieldBleed
- 5. GHSL-2026-045_Wekan ImportLegacyBleed
- Affected Wekan v8.33 and earlier
- Fixed at
Wekan v8.34 2026-02-20
- More details
|
-
|
|
FloppyBleed |
2026-01-24 18:30 EET |
Luke Hebenstreit of Twitter lheben_
|

|
Process
Did send detailed report!
|
Details
|
-
|
|
SnowBleed |
2026-01-05 15:46 EET |
Joshua Rogers of Aisle Research
|

|
Process
Did send detailed report!
|
Details
- 1. SnowBleed
- 2. OrgsTeamsBleed
- 3. ChecklistRESTBleed
- 4. MigrationsBleed2
- 5. PositionHistoryLegacyBleed
- 6. SyncLDAPBleed
- 7. AttachmentMigrationBleed
- 8. MoveStorageBleed
- 9. ListWIPBleed
- 10. BoardTitleRESTBleed
- 11. CardPubSubBleed
- 12. FixDuplicateBleed
- 13. LinkedBoardActivitiesBleed
- 14. RulesBleed
- Affected Wekan v8.19
- Fixed at
Wekan v8.20 2026-01-16 and
Wekan v8.21 2026-01-18
- More details
|
-
|
|
MegaBleed |
2025-12-26 18:39 EET |
Joshua Rogers of Aisle Research
|

|
Process
Did send detailed report!
|
Details
- 1. IDOR in setCreateTranslation. Non-admin could change Custom Translation
- 2. Private-only board setting can be bypassed
- 3. Card comment author spoofing (IDOR) via API
- 4. Cross-board card move without destination authorization
- 5. Read-only roles can still update cards
- 6. Checklist delete IDOR: checklist not verified against board/card
- 7. Checklist create IDOR: cardId not verified against boardId
- 8. Attachments publication leaks metadata without auth
- 9. Attachment upload not scoped to card/board relationship
- 10. LDAP filter injection in LDAP auth
- Affected Wekan v8.18
- Fixed at Wekan v8.19 2025-12-29
- More details
|
-
|
|
SpaceBleed |
2025-11-02 03:29 EET |
Siam Thanat Hack (STH)
|

|
Process
Did send detailed report!
|
Details
- 1. File Attachments enables stored XSS (High)
- 2. Access to boards of any Orgs/Teams (High)
- 3. Unauthenticated (or any) user can update board ‘sort’ (Low)
- 4. Members can forge others’ votes (Low)
Bonus: Similar fixes to planning poker too done by xet7.
- 5. Attachment API uses bearer value as userId and DoS (Low)
- Affected Wekan v8.15
- Fixed at Wekan v8.16 2025-11-02
- More details
|
CVE-2021-20654
JVN: Many fixed.
|
|
FieldBleed |
JVN: 2021-2025 Many fixed.
|
Cyb3rjunky and swsjona about input fields.
Ryoya Koyama at Mitsui Bussan Secure Directions, Inc. (https://www.mbsd.jp/) about
Javascript inside .SVG attachment
Romain Korpas at apitech.fr about IDOR.
Nguyen Thanh Nguyen of Fortinet's FortiGuard Labs about SVG.
Sho Sugiyama about XSS. And some anonymous security researchers.
|

|
Process
Did send detailed report!
|
Details
- XSS: Javascript saved to field, and Javascript inside .SVG attachment, is run when page is reloaded
- Affected Wekan v3.12-v4.11
- Fixed at Wekan v4.12 2020-06-08
- More details
- Fixed at WeKan v7.98 or earlier:
- IDOR CWE-639 that affected WeKan 7.80-7.93: Romain Korpas at apitech.fr.
- Computational Resource Abuse in Export endpoints: Anynymous Security Researcher.
- FG-VD-22-078 Prevent SVG Billion Laughs Attack: Nguyen Thanh Nguyen of Fortinet's FortiGuard Labs.
- usd-2022-0041 CWE-284 Improper Access Control: Christian Pöschl of usd AG.
- JVN#14269684 Broken access control, JVN#74210258 Stored XSS, JVN#86586539 Stored XSS: Ryoua Koyama.
- JVN#15385465 CWE-79 XSS: Sho Sugiyama.
- JVN#80785288 CWE-79 XSS: Already previously fixed.
|
|
-
|
|
SocialBleed |
2023-05-11 19.14 EET |
Rajesh Thapa
|

|
Process
Did send detailed report!
|
Details
- Security: Links to Social Media at wekan.fi could lead to theft of sensitive information
- Affected Wekan website before 2024-05-12 05.34 EET
- Fixed at Wekan website 2023-05-12 05.34 EET
- More details
|
|
-
|
|
AdminBleed |
2023-04-24 16.40 EET |
Christian Pöschl of usd AG Responsible Disclosure Team
|

|
Process
Did send detailed report!
|
Details
- Security: Non-Admin could change to Admin
- Affected Wekan v6.85 and earlier
- Fixed at Wekan v6.86 2023-04-26
- More details
|
|
-
|
|
InvisibleBleed |
2023-04-24 03.35 EET |
Someone at chat
|

|
Process
Sent report and disappeared.
|
Details
- Security: HTML comments not visible
- Affected Wekan v6.85 and earlier
- Fixed at Wekan v6.86 2023-04-26
- More details
|
|
CVE-2023-31779
|
|
ReactionBleed |
2023-02-28 12.36 EET |
Alexander Starikov at Jet Infosystems
|
 
|
Process
Did send detailed report and fix!
|
Details
|
|
-
|
|
FileNameBleed |
2023-02-16 17.35 EET |
SEC Consult, an Atos company
|

|
Process
Did send detailed report!
|
Details
|
|
-
|
|
Emailbleed |
2021-01-26 12.42 EET |
Georg Krause
|

|
Process
Did send detailed report!
|
Details
- Security: SMTP password visible to Admin at Admin Panel by using browser inspect to see behind asterisks
- Affected Wekan v1.59-v4.98
- Fixed at Wekan v4.99 2021-02-25
- More details
|
|
CVE-2021-3309
|
|
LDAPBleed |
2021-01-26 0:42 EET |
robert-scheck
|
 
|
Process
Did send report and sent fix! Although, report was at public GitHub issue, not via Responsible Security Disclosure
|
Details
|
|
-
|
|
DUEBleed |
2021-01-11 EET |
xet7
|
 
|
Process
Did not notice security issue originally when merging new feature from pull request. Did fix issue when finally noticed it at production at Wekan demo server.
|
Details
- Due Cards and Broken Cards: As Admin user, at All Users view of Due Cards and Broken Cards,
fixed to not show cards from other users private boards. This affected only logged in Admin user,
not logged in other users.
- Affected Wekan v4.73-v4.74
- Fixed at Wekan v4.75 2021-01-11
- More details
|
|
VRF#20-08-SGSSC.
|
|
BypassBleed |
2020-02-26 01:36 EET |
Dejan Zelic, Justin Benjamin and others at Offensive Security
|
 
|
Process
Did send detailed report and helped fixing!
|
Details
|
|
VRF#20-08-DDFJJ.
|
|
UserBleed |
2018-06-12 |
Adrian Genaid at PLANTA Projektmanagement-Systeme GmbH
|
 
|
Process
Did send detailed report and fix!
|
Details
|
CVE-2018-1000549, In Progress Update Request 938446
|
|
BruteBleed |
2018-06-12 |
Shadow Vault
|

|
Process
Did not report to Wekan, was found later from CVE
|
Details
|
|
VRF#20-08-LZGVF.
|
|
FrameBleed |
2018-03-25 |
Team
|

|
Process
Did send detailed report!
|
Details
- Cross Frame Scripting
- Clickjacking
- Improper Cache Control
- Affected Wekan v0.7-v0.79
- More details
|