Vikunja's patch streak: 29 advisories, four releases, one default that bites

Test excerpt.

Share
A self-hosted task board on one screen, and a session token drifting across to another page on the same machine
A self-hosted task board on one screen, and a session token drifting across to another page on the same machine. In affected Vikunja versions, any page served from localhost could read the token-refresh response and take over the logged-in session.

The 29-advisory batch is not 29 new vulnerabilities

On October 9, 2026, 29 GitHub Security Advisories for the code.vikunja.io/api package appeared in the GitHub global advisory feed within roughly 20 minutes. Six of them were new: published in the vendor's repository on October 3 and fixed in v2.7.0, released October 2. The other 23 were older advisories, published in the repository on July 19, August 4, and August 31, fixed in v2.4.0, v2.5.0, and v2.6.0 respectively, which the global feed published in the same batch. The October 9 date is a bulk (re)publication, not the date the flaws were found or fixed.

The vendor's own changelog post for v2.7.0 says the release "fixes six security vulnerabilities, one high and five medium," and the author adds: "At this point, I wonder whether we will get a release without security fixes any time soon. Thanks AI!" Security fixes have shipped in every release from v2.4.0 (July 19, 2026) through v2.7.0 (October 2, 2026).

The CORS default that hands over your session

The high-severity fix in v2.7.0 (GHSA-m687-p538-r5hp, CVSS 4.0 7.2) is a permissive cross-domain security policy (CWE-942). Vikunja's cors.origins setting defaults to localhost wildcards with Access-Control-Allow-Credentials: true, and service.publicurl is appended to the defaults rather than replacing them.

The practical consequence: any page served from any localhost port can make a credentialed request to the token-refresh endpoint and read the returned bearer JWT. A single fetch() from a browser tab on the same machine takes over the logged-in user's session. A working proof-of-concept is attached to the advisory, built from commit a881ac3 with sqlite, where one fetch() yields a working access token. The flaw was found with Google's security automation tooling and triaged by Ada Logics.

For self-hosters, this matters in one specific way. If Vikunja runs on the same machine as other local web services, a common setup for homelabs, any of those local pages can steal the session of anyone logged into Vikunja.

The account-takeover trio in v2.4.0

The July 19 batch, fixed in v2.4.0, contains three account-takeover flaws:

  • CVE-2026-62367: OIDC emailfallback links an SSO login to a local account on the email claim alone, never checking email_verified. A token carrying the victim's email logs in as that victim (1.0.0 through 2.3.0).
  • CVE-2026-62376: password-reset, email-confirmation, and account-deletion tokens are stored in plaintext in the user_tokens table. Database read access is immediate account takeover (before 2.4.0).
  • CVE-2026-57458: a scoped API token limited to oauth.authorize can mint an unrestricted bearer JWT plus a refresh token (2.3.0).

Cross-tenant authorization flaws

Four advisories cross tenant boundaries:

  • CVE-2026-68582 (CRITICAL, CVSS 4.0 9.3): a BOLA in the task-collection endpoint. Any link-share token holder can read any other tenant's kanban bucket records, including created_by user objects (0.24.0 through 2.3.0, fixed in 2.4.0).
  • CVE-2026-68581: a link-share JWT whose numeric ID equals a user ID is treated as that user at the token-management endpoints, allowing list, create, and delete of the target user's API tokens (0.22.0 through 2.3.0).
  • CVE-2026-76216: principal-type confusion at three permission checks. An attacker can remove victims from teams, enumerate and delete victim bot users, and read team rosters (through 2.4.0, fixed in 2.5.0).
  • CVE-2026-91984: an unvalidated project_view_id in task-position requests lets an authenticated attacker insert task position rows into arbitrary other tenants' project views (before 2.6.0, fixed in 2.6.0).

The 18-advisory DoS and information-disclosure batch

The August 31 batch (18 advisories, fixed in v2.5.0 and v2.6.0) is dominated by denial-of-service and information-disclosure issues: a decompression bomb in data import, unbounded recursion in nested task filters, unbounded CSV row cardinality, unbounded image decode, unthrottled pre-authentication /api/v2 endpoints, CalDAV and feed BasicAuth endpoints without rate limits, a TOTP secret readable after enrollment without step-up, API token scopes bypassed via the task expand parameter, assignee email disclosed to read-only members, and cross-project task disclosure through subtask expansion.

What this means for self-hosters

Three things stand out. First, the 2.6.0 permission regression: an explicit lower-permission sub-project share is silently overridden by an inherited parent permission, one of the five medium fixes in v2.7.0. Second, the pattern: security fixes in every release for three months signals an actively audited codebase, with the fixes actually landing. The vendor's own changelog note credits AI tooling in that process. Third, the CORS default is the one to check first. If you run Vikunja on the same host as other local web services, verify that cors.origins does not include localhost wildcards with credentials allowed.

Exploitation status: PoC available (the CORS advisory), no confirmed wild exploitation. No CISA KEV listing as of October 12, 2026.

Sources

This article was drafted with AI/LLM assistance and reviewed by a human before publication. All factual claims were checked against the public sources cited above. The feature image was generated with AI. See How we use AI for the full workflow.

Topics: