Skip to content

wekan

v9.32 Security

This release includes 4 security fixes for security teams reviewing exposed deployments.

Published 3d Productivity & Wikis
✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →
This release patches 4 known CVEs

Topics

docker javascript kanban meteor real-time sandstorm
+2 more
snapcraft wekan

Affected surfaces

auth rbac rce_ssrf

ReleasePort's take

Moderate signal
editorial:auto 3d

The v9.32 release adds input‑side validation for webhook URLs to prevent SSRF and enforces write‑level authorization for Custom Field mutations, among other security fixes.

Why it matters: Security fixes address CVEs with severity scores of 100 (GHSA-hc3x‑hq3m‑663q) and 90 (GHSA-6733‑4wgq‑8xvr), directly mitigating SSRF risk and privilege escalation for webhook integrations and custom field operations.

Summary

AI summary

Broad release touches https://github.com/wekan/wekan/commit/0e5fef6f31164fd3de4db353d04173ee0490cd65, SSRF, CWE-918, and https://github.com/wekan/wekan/commit/92beaa313706bc26fbea7e1cc8cfaf836609e038.

Changes in this release

Security Critical

Fixes GHSA-hc3x-hq3m-663q: adds input-side validation for webhook URLs, preventing SSRF.

Fixes GHSA-hc3x-hq3m-663q: adds input-side validation for webhook URLs, preventing SSRF.

Source: llm_adapter@2026-05-31

Confidence: high

Security Critical

Fixes GHSA-7w2h-g83c-jqrp: requires board admin for copyBoard DDP method, preventing unauthorized board copying.

Fixes GHSA-7w2h-g83c-jqrp: requires board admin for copyBoard DDP method, preventing unauthorized board copying.

Source: llm_adapter@2026-05-31

Confidence: high

Security Critical

Fixes GHSA-cv95-8h7c-2ffq: blocks direct client calls to six OIDC Meteor methods, preventing privilege escalation.

Fixes GHSA-cv95-8h7c-2ffq: blocks direct client calls to six OIDC Meteor methods, preventing privilege escalation.

Source: llm_adapter@2026-05-31

Confidence: high

Security Critical

Fixes GHSA-mp7g-hj5q-gxhq: disables unconditional OIDC account merging, requiring verified email and opt‑in setting.

Fixes GHSA-mp7g-hj5q-gxhq: disables unconditional OIDC account merging, requiring verified email and opt‑in setting.

Source: llm_adapter@2026-05-31

Confidence: high

Security Critical

Fixes GHSA-6733-4wgq-8xvr: enforces write‑level authz for Custom Field mutations, preventing read‑only privilege escalation.

Fixes GHSA-6733-4wgq-8xvr: enforces write‑level authz for Custom Field mutations, preventing read‑only privilege escalation.

Source: llm_adapter@2026-05-31

Confidence: high

Feature Low

Adds test menu options for Playwright Chromium, Firefox, and WebKit in rebuild‑wekan.sh.

Adds test menu options for Playwright Chromium, Firefox, and WebKit in rebuild‑wekan.sh.

Source: llm_adapter@2026-05-31

Confidence: high

Feature Low

Copies wepica style hide/show password UI to WeKan login and register pages.

Copies wepica style hide/show password UI to WeKan login and register pages.

Source: llm_adapter@2026-05-31

Confidence: high

Feature Low

Adds global "Roles" tab in Admin Panel to control which board roles can invite users.

Adds global "Roles" tab in Admin Panel to control which board roles can invite users.

Source: llm_adapter@2026-05-31

Confidence: high

Dependency Low

Updates multiple dependencies across eight commits, including meteor-node-stubs fork.

Updates multiple dependencies across eight commits, including meteor-node-stubs fork.

Source: llm_adapter@2026-05-31

Confidence: high

Bugfix Medium

Restores external antivirus scanner functionality broken by avatar RCE fix.

Restores external antivirus scanner functionality broken by avatar RCE fix.

Source: llm_adapter@2026-05-31

Confidence: high

Full changelog

This release fixes the following CRITICAL SECURITY ISSUES:

  • Fix GHSA-hc3x-hq3m-663q: Server-Side Request Forgery (SSRF) via webhook integration URLs (CWE-918).
    Wekan's outgoing-webhook integrations let a board
    admin store an arbitrary URL that is later fetched server-side, so a
    caller-controlled URL pointing at an internal address (cloud metadata at
    http://169.254.169.254/latest/meta-data/, loopback, RFC 1918 ranges, etc.)
    could be used to reach internal services or exfiltrate data.
    • Originally fixed at the delivery layer in v8.35 and v8.36 (the
      IntegrationBleed fixes).
      Fix IntegrationBleed (v8.35)
      routed webhook delivery in server/notifications/outgoing.js through
      fetchSafe (server/lib/ssrfGuard.js), which validates the URL and blocks
      private/loopback IPs, and
      Fix RebindBleed of IntegrationBleed (v8.36)
      hardened it further to resolve DNS once, pin the connection to the validated
      IP, and block redirects — closing the actual request-time SSRF including DNS
      rebinding.
    • New in this release: the missing input-side validation the advisory
      requested, added at the REST write paths in server/models/integrations.js.
      Those endpoints accepted webhook URLs without a robust check:
      POST /api/boards/:boardId/integrations relied only on the schema's regex
      custom() validator (no DNS resolution, blind to a hostname that resolves to
      a private IP and to decimal/octal/IPv4-mapped-IPv6 encodings), and
      PUT /api/boards/:boardId/integrations/:intId wrote the URL via
      Integrations.direct.updateAsync, which bypasses schema validation entirely,
      so updated URLs were never validated at the data layer. Both endpoints now run
      the DNS-aware validateAttachmentUrl()
      (models/lib/attachmentUrlValidation.js, the same validator already used for
      attachment imports) before storing the URL, rejecting
      private/loopback/link-local/reserved targets with HTTP 400. Together with the
      v8.35/v8.36 fetchSafe delivery guard and the schema validator on
      client-side inserts/updates, webhook URLs are now validated on every write
      path and again at delivery.
      Thanks to Claude.
  • Fix GHSA-7w2h-g83c-jqrp: Authorization bypass in copyBoard DDP method allows any user to copy private boards (CWE-862).
    The copyBoard Meteor method in server/publications/boards.js
    had no authorization check: any logged-in user
    could copy any board by ID — including private boards they are not a member of —
    cloning all cards, checklists, custom fields, labels and rules, while the
    equivalent REST endpoint POST /api/boards/:boardId/copy correctly required
    board admin. The method also looped over caller-supplied properties
    (for (const key in properties) board[key] = properties[key]) and copied them
    onto the new board, letting an attacker inject arbitrary fields such as
    members (to add themselves as admin of the copy) or permission: 'public'
    (to expose the copy to everyone). The member-level fix shipped in v9.09 as part
    of the AuthBleed fixes (caller must be authenticated, board must exist, caller
    must be a board member, and members/permission are stripped from
    properties before the copy). This release tightens it further to full parity
    with the REST endpoint: copyBoard now requires the caller to be a board admin
    (board.hasAdmin(this.userId), the same {isActive:true, isAdmin:true}
    condition the REST API enforces via checkAdminOrCondition) rather than merely
    a member.
  • Fix GHSA-cv95-8h7c-2ffq: Missing authorization on OIDC Meteor methods allows privilege escalation to admin (CWE-269, CWE-862).
    Six Meteor methods used internally by the OIDC login flow were registered as globally DDP-callable
    with no authorization, while their non-OIDC counterparts require admin. setCreateOrgFromOidc and
    setOrgAllFieldsFromOidc (server/models/org.js), setCreateTeamFromOidc and
    setTeamAllFieldsFromOidc (server/models/team.js) let any authenticated user create/rename/
    deactivate/modify arbitrary organizations and teams — including orgAutoAddUsersWithDomainName
    bypassing the admin-only restriction. Most critically, groupRoutineOnLogin
    (packages/wekan-oidc/oidc_server.js) sets isAdmin from caller-supplied group data, so with
    PROPAGATE_OIDC_DATA enabled any authenticated user could call it over DDP with
    {groups:[{isAdmin:true,forceCreate:true}]} and promote themselves to global admin;
    boardRoutineOnLogin could likewise add the caller to the default board. These six methods are only
    ever invoked server-side (via Meteor.callAsync) during the OIDC handshake, where a fix that checks
    isAdmin/this.userId would break legitimate group/admin propagation (the user is not yet logged in
    or admin at that point). Fixed by rejecting any direct client/DDP invocation: a server-to-server
    Meteor.callAsync runs with this.connection === null, whereas a client call has a non-null
    connection, so each of the six methods now throws not-authorized when this.connection !== null.
    The legitimate OIDC login flow is unaffected.
    Thanks to alexwaira for the coordinated disclosure, and Claude.
  • Fix GHSA-mp7g-hj5q-gxhq: OIDC Account Takeover via Unconditional Email-Based Account Merge in Accounts.onCreateUser hook (CWE-287).
    The onCreateUser hook in server/models/users.js unconditionally merged an incoming OIDC login
    into any existing Wekan account whose email or username matched the (attacker-controlled) OIDC
    claims — no ownership check, no email-verification check, no notification. An attacker who could
    present a matching email/username claim (trivial on self-hosted Keycloak/Authentik, where the
    email/email_verified claims are attacker-settable) inherited the victim's _id, boards, cards,
    attachments, API tokens and admin status, all during the attacker's own first OIDC login with no
    victim interaction. Fixed to fail closed, mirroring LDAP_MERGE_EXISTING_USERS: matching is now by
    email only (never username); auto-linking is opt-in via the new OAUTH2_MERGE_EXISTING_USERS
    setting (OFF by default, so the default deployment never merges); even when enabled the OIDC
    provider must assert email_verified=true; otherwise the OIDC login is rejected with
    oidc-email-already-in-use instead of merging. The provider's email_verified claim is now
    captured into the OIDC service data in packages/wekan-oidc/oidc_server.js.
    Thanks to alexwaira for the coordinated disclosure, and Claude.
  • Fix GHSA-6733-4wgq-8xvr: Read-only board members could create/modify/delete Custom Fields.
    (privilege escalation via read-level authz on write operations, CWE-862).
    All six mutating REST handlers in server/models/customFields.js (POST/PUT custom-fields,
    POST/PUT/DELETE dropdown-items, DELETE custom-fields) called the read-level
    Authentication.checkBoardAccess instead of the write-level checkBoardWriteAccess, letting a
    board member with the read-only role (isReadOnly / isReadAssignedOnly) write Custom Field
    data via the REST API when WITH_API=true. Replaced the check with checkBoardWriteAccess in
    all six mutating handlers (the two GET handlers correctly stay on checkBoardAccess), mirroring
    lists.js/swimlanes.js/cards.js.
    Thanks to Wernerina for the coordinated disclosure, and Claude.
  • Fix regression from the avatar RCE fix GHSA-35j7-h385-2q9g: external antivirus scanner broken (asyncExec undefined).
    The avatar RCE fix renamed asyncExec to asyncExecFile in models/fileValidation.js, but the
    admin-configured external scanner command line still called the now-undefined asyncExec, throwing
    ReferenceError (swallowed by the catch) and making every upload silently fail validation whenever
    an external scanner was configured. Restored a shell-based asyncExec used only for that
    admin-configured command line; MIME detection still uses the shell-free asyncExecFile.
    Thanks to Claude.
  • Fix CodeQL 68: Polynomial regex DoS in Jade parser.
    Thanks to CodeQL and Claude.
  • Fix CodeQL 69: Polynomial regex DoS in Jade parser, part 2.
    Remove the redundant $ anchor from the interpolation regex in compiler.js and bundled jade.js.
    The greedy [\s\S]* already matches to end of string, so dropping $ keeps the same match
    while eliminating the backtracking that CodeQL alert js/polynomial-redos flagged.
    Thanks to CodeQL and Claude.
  • Fix CodeQL 63: Incomplete string escaping or encoding in bundled jade.js.
    In uglify-js's make_string (bundled twice into jade's browser bundle), the chosen
    quote was escaped in a trailing str.replace(/'/g, "\\'") that CodeQL alert
    js/incomplete-sanitization flags for not escaping backslashes in that same call.
    Backslashes were already escaped in the earlier single-pass replace, so this was a
    local false positive, but the fix folds the quote escaping into that same pass
    (escaping both quotes), making the escaping atomic and complete while keeping the
    emitted string literals decode-equivalent.
    Thanks to CodeQL and Claude.
  • Fix CodeQL 67: Incomplete multi-character sanitization.
    Thanks to CodeQL and GitHub Copilot.
  • Fix CodeQL 60: Useless regular-expression character escape.
    Thanks to CodeQL and GitHub Copilot.
  • Fix CodeQL 58: Incomplete multi-character sanitization.
    Thanks to CodeQL and GitHub Copilot.
  • Fix CodeQL 57: Incomplete multi-character sanitization.
    Thanks to CodeQL and GitHub Copilot.
  • Fix CodeQL 56: Incomplete string escaping or encoding](https://github.com/wekan/wekan/commit/c5e42607af5a0a396c0c85dba3652b8be28a2ff3).
    Thanks to CodeQL and GitHub Copilot.
  • Fix CodeQL 55: Incomplete string escaping or encoding.
    Thanks to CodeQL and GitHub Copilot.
  • Fix CodeQL 48: Clear-text logging of sensitive information.
    Thanks to CodeQL and GitHub Copilot.
  • Fix CodeQL 418: Clear-text logging of sensitive information.
    Thanks to CodeQL and GitHub Copilot.
  • Fix CodeQL 419: Clear-text logging of sensitive information.
    Thanks to CodeQL and GitHub Copilot.
  • Delete calendar demos, so that CodeQL stops complaining.
    Thanks to xet7.
  • Fix CodeQL 35: Insecure randomness.
    Thanks to CodeQL and GitHub Copilot.
  • Fix CodeQL 417: Workflow does not contain permissions.
    Thanks to CodeQL and GitHub Copilot.

and adds the following updates:

and adds the following new features:

  • Add User board access roles to Admin Panel / People / Roles.
    A new global "Roles" tab in Admin Panel / People lets a site admin choose which
    board roles are allowed to invite users to a board ("Allow Invite to Board").
    Each board role has its own toggle — Board Admin, Normal, Worker, Comment only,
    No comments, Only Assigned Normal, Only Assigned Comment, Read Only and Only
    Assigned Read — plus an "All Board Members" master toggle that selects them all.
    The policy is enforced server-side in the inviteUserToBoard and searchUsers
    methods, and the add-member button in the board sidebar is shown only to roles
    the policy allows. Global Admin Panel users (site admins) always have all rights
    and cannot be restricted here; this is kept clearly distinct in code from the
    per-board "Board Admin" role. Secure default: only Board Admin and Normal may invite.
    Thanks to xet7.

and fixes the following bugs:

Thanks to above GitHub users for their contributions and translators for their translations.

Security Fixes

  • GHSA-hc3x-hq3m-663q – SSRF via webhook integration URLs (CWE‑918) fixed by DNS‑aware URL validation at write paths and fetchSafe guard
  • GHSA-7w2h-g83c-jqrp – Authorization bypass in copyBoard DDP method now requires board admin
  • GHSA-cv95-8h7c-2ffq – Missing authorization on OIDC Meteor methods rejected for client‑side calls
  • GHSA-mp7g-hj5q-gxhq – Unconditional email/username merge during OIDC account creation prevented; now opt‑in, requires email_verified=true

Weekly OSS security release digest.

The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.

No spam, unsubscribe anytime.

Share this release

Track wekan

Get notified when new releases ship.

Sign up free

About wekan

The Open Source kanban, built with Meteor. GitHub issues/PRs are only for FLOSS Developers, not for support, support is at https://wekan.fi/commercial-support/ . New English strings for new features at imports/i18n/data/en.i18n.json . Non-English translations at https://app.transifex.com/wekan/wekan only.

All releases →

Related context

Related tools

Beta — feedback welcome: [email protected]