CVE-2026-68581: vikunja · Incorrect Authorization
Affects vikunjaSource CVE Database V5
Not known to be exploited · CVSS 8.6 High : upgrade to 2.4.0 soon.
Data as of 31 Oct 2026, 08:20 UTC
- EPSS
- 0.4% chance of exploitation in 30 days – higher than 40% of CVEsExploit Prediction Scoring System: the likelihood attackers will use this flaw soon.
- Patch
- Available – fixed in 2.4.0
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:NExploitation evidence
Disclosed: evidence found.
CVE published 2 Aug 2026
Detectable: no evidence on record.
No public nuclei template indexed
Weaponized: no evidence on record.
No public exploit code indexed in Metasploit or Exploit-DB
Exploited in the wildExploited: no evidence on record.
Not in CISA KEV and no source reports exploitation
Observed by OffSeq MirageSeen by Mirage: no evidence on record.
No attack traffic recorded by OffSeq Mirage sensors
A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 30 Oct 2026.
What to do
Upgrade vikunja to 2.4.0.
Affected software
| Product | Affected | Fixed in |
|---|---|---|
| go-vikunjavikunja | Affected
| Fixed in
|
Gogithub.com/go-vikunja/vikunjapkg:golang/github.com/go-vikunja/vikunjaOther threats | Affected
| Fixed in– |
Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.
AI-suggested
Upgrade to Vikunja version 2.4.0 or later, where this authorization flaw is fixed. No other official remediation or temporary workaround is indicated. Patch status is not explicitly stated but the fix version is known.
Description
Executive Summary Vikunja accepts both regular-user JSON Web Tokens (JWTs) and link-share JWTs through its generic authenticated API route group. A link-share JWT resolves to a `models.LinkSharing` principal whose `GetID()` method returns the numeric `link_shares.id`. The API-token management model then treats that generic numeric value as a `users.id` when it creates, lists, and deletes API tokens. Because `users.id` and `link_shares.id` are independent positive sequences, a link share whose ID equals another user's ID is treated as that user by `/api/v1/tokens`. An ordinary authenticated attacker can obtain a target's numeric user ID through authenticated user search and create link shares on an attacker-writable project until the link-share sequence reaches that value. The colliding link-share principal can then list the target's API-token metadata, issue a new API token owned by the target, and delete target-owned API tokens. The newly issued token operates with attacker-selected valid API scopes under the target user's existing permissions. I reviewed the vulnerable `v2.3.0` source, the introducing commit, the stable tag history, and the inspected main revision directly. I also reviewed the recorded local HTTP and native-router validation results. Dynamic testing used only a local `v2.3.0` Docker deployment with PostgreSQL and synthetic data; I did not test any public, hosted, or otherwise external instance. Historical tags were checked from source rather than exercised dynamically. | Field | Value | | --- | --- | | Product | Vikunja API | | Status | Validated; disclosure-ready | | Confirmed affected stable versions | `v0.22.0` through `v2.3.0`, inclusive | | Nearest confirmed unaffected stable version | `v0.21.0` | | Introducing commit | `e6b25bd57b537ef9a72b5acdadf446ca5ef77bfa` | | Latest inspected affected main revision | `95b7e673fb5ee407498fa4b13e8b4c57847a4a0b` | | Fixed version | Unknown; no verified fix commit or release was identified | | Severity | High, CVSS v3.1 score 8.1 | | Vector | `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N` | | Weakness | Primary: CWE-863 (Incorrect Authorization); secondary: CWE-639 | The stable range is source-based. The issue first became reachable when commit `e6b25bd57b...` added the authenticated API-token CRUD routes while retaining the generic `web.Auth.GetID()` ownership model. `v0.21.0` does not contain the API-token model or these routes. All containing stable tags from `v0.22.0` through `v2.3.0` retain the vulnerable source-to-sink tuple. Downstream forks and vendor-specific builds were not assessed. ## Background ### Two authenticated principal types share one numeric interface Vikunja's authenticated route group is protected by a common token middleware. That middleware can establish a regular user, an API-token owner, or a link share as the request's `web.Auth` principal. The `/api/v1/tokens` handlers are registered on this generic group in `pkg/routes/routes.go`: ```go a.Use(SetupTokenMiddleware()) // API Tokens apiTokenProvider := &handler.WebHandler{ EmptyStruct: func() handler.CObject { return &models.APIToken{} }, } a.GET("/tokens", apiTokenProvider.ReadAllWeb) a.PUT("/tokens", apiTokenProvider.CreateWeb) a.DELETE("/tokens/:token", apiTokenProvider.DeleteWeb) ``` The security-sensitive detail is that authentication answers *which object is the principal*, while `web.Auth.GetID()` exposes only an untyped integer. A regular user's ID belongs to the `users` namespace. A link-share ID belongs to the separately allocated `link_shares` namespace. Equality between those integers does not imply that the principals represent the same actor. ### Link-share authentication preserves the share-row ID `pkg/modules/auth/auth.go` creates a link-share JWT with the share's numeric ID and later resolves that token to a `models.LinkSharing` object: ```go claims["type"] = AuthTypeLinkShare claims["id"] = share.ID claims["hash"] = share.Hash claims["project_id"] = share.ProjectID // ... if typ == AuthTypeLinkShare && config.ServiceEnableLinkSharing.GetBool() { s := db.NewSession() defer s.Close() return models.GetLinkShareFromClaims(s, claims) } ``` The `LinkSharing` model declares its own positive auto-incrementing key and returns it unchanged through the generic interface in `pkg/models/link_sharing.go`: ```go type LinkSharing struct { ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"share"` // ... } func (share *LinkSharing) GetID() int64 { return share.ID } ``` Link shares are expected to act within the shared project's permission boundary. API-token management is instead a user-account credential boundary: tokens are owned by users and can authorize future requests as those users. The normal invariant should therefore be that only a positively identified regular-user principal may enter API-token management, and its user ID must be used as the owner key. ### Attacker capabilities The validated attacker is an ord
References
- github.com/go-vikunja/vikunja/security/advisories/GHSA-vvcv-vpph-h844 (opens in a new tab)
- github.com/go-vikunja/vikunja/commit/e6b25bd57b537ef9a72b5acdadf446ca5ef77bfa (opens in a new tab)
- github.com/go-vikunja/vikunja/commit/95b7e673fb5ee407498fa4b13e8b4c57847a4a0b (opens in a new tab)
- vulncheck.com/advisories/vikunja-through-authentication-bypass-via-principal-id-collision (opens in a new tab)