Every CVE Search/ Get API key

CVE-2026-76216

Vikunja through 2.4.0 Principal-Type Confusion via LinkSharing

7.7 HighFix available

Vikunja through 2.4.0 contains a principal-type confusion vulnerability where LinkSharing principals with id N are treated as user principals with users.id == N at three permission checks lacking type guards. Attackers with a link-share JWT can remove victims from teams, enumerate and delete victim bot users, or read team rosters by exploiting id collisions in the autoincrement space.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
High
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
High

Exploit likelihood

0.36%Up 0.1 points since Aug 20, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.7

Vikunja through 2.4.0 Principal-Type Confusion via LinkSharing

Vikunja through 2.4.0 contains a principal-type confusion vulnerability where LinkSharing principals with id N are treated as user principals with users.id == N at three permission checks lacking type guards. Attackers with a link-share JWT can remove victims from teams, enumerate and delete victim bot users, or read team rosters by exploiting id collisions in the autoincrement space.

Record
CVE-2026-76216
CVSS 4.0
7.7 HighCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-639
Updated
2026-11-02
EUVDEUVD-2026-62457 7.7

Vikunja through 2.4.0 contains a principal-type confusion vulnerability where LinkSharing principals with id N are treated as user principals with users.id == N at three permission checks lacking type guards. Attackers with a link-share JWT can remove victims from teams, enumerate and delete victim bot users, or read team rosters by exploiting id collisions in the autoincrement space.

Record
EUVD-2026-62457
CVSS 4.0
7.7 HighCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-32r8-5843-4qw2 7.5

Vikunja: Link-share principal-type confusion enables cross-account team removal, bot takeover, and roster disclosure

Summary

Vikunja's web.Auth interface (pkg/web/web.go, single method GetID() int64) is satisfied by BOTH *user.User and *models.LinkSharing. A link-share's GetID() returns the raw positive share.ID (pkg/models/link_sharing.go:83-85), which lives in the same positive autoincrement ID space as users.id. The safe negated form getUserID() = share.ID * -1 (link_sharing.go:126-128) exists but is NOT used at three permission sinks. As a result, a link-share principal with id N — which should have zero authority over teams or bot users — is treated as the user whose users.id == N at three permission checks that lack the a.(*LinkSharing) guard their sibling methods have. This is the same principal-type-confusion class as CVE-2026-68581 (GHSA-vvcv-vpph-h844), but at three code paths that advisory/fix never touched.

Root Cause

web.Auth is a one-method interface (GetID() int64). *LinkSharing.GetID() returns the raw positive share id. Three permission methods compare this raw id directly and omit the link-share type guard used elsewhere in the same files:

  1. TeamMember.CanDelete (pkg/models/team_members_permissions.go:31-40): the self-removal fast path if u.ID == a.GetID() { return true } (:36) executes before IsAdmin. IsAdmin (:48-51) is the ONLY place that rejects link shares (if _, is := a.(*LinkSharing); is { return false }, :50) — and it is never reached when the fast path returns true.
  2. BotUser.isOwner (pkg/models/bot_users_permissions.go:47-56): return u.BotOwnerID == a.GetID() (:55), used by CanRead/CanUpdate/CanDelete (:36-45). Unlike CanCreate (:27-30) which type-asserts a.(*user.User), these three paths have no principal guard.
  3. Team.CanRead (pkg/models/teams_permissions.go:68-78): matches membership on And("user_id = ?", a.GetID()) (:76) with no link-share guard, unlike sibling IsAdmin (:45-49, guard at :47).

Link-share JWTs reach these routes: SetupTokenMiddleware validates the signature only, GetAuthFromClaims returns *models.LinkSharing, and the /user//teams route groups add no link-share rejection. Link sharing is enabled by default (config.go ServiceEnableLinkSharing.setDefault(true)).

Impact

A link-share principal (obtainable from any public share link, or self-registered via a share on the attacker's own project) whose id N collides with a victim's users.id == N can, without being that user or any user:

  • Integrity (I:H): remove the victim from any team they belong to (DELETE /api/v1/teams/{T}/members/{username}) → revokes all project permissions the victim inherited through that team.
  • Availability/Integrity (A:H, I:H): enumerate the victim's bot users (GET /api/v1/user/bots → bot_owner_id = a.GetID()), then disable/rename or permanently delete them (DELETE /api/v1/user/bots/{id} → DeleteUser), destroying data owned solely by those bots.
  • Confidentiality (C:H): read the roster + metadata (name, description, full member list) of any team the colliding user belongs to (GET /api/v1/teams/{T}), plus read bot-user records via isOwner-gated reads.

Attack Chain

Sink 1 — TeamMember.CanDelete (integrity)

  1. Entry: POST /api/v1/shares/{hash}/auth → link-share JWT with id = N. Guard: JWT middleware — signature only. Bypass proof: GetAuthFromClaims returns *models.LinkSharing; no route-group link-share rejection on the /teams group.
  2. Action: DELETE /api/v1/teams/{T}/members/{usernameOfUserN} with the link-share bearer, targeting a team T (≥2 members) that user N belongs to. Guard: CanDelete → GetUserByUsername(tm.Username) returns user N, then u.ID == a.GetID() (team_members_permissions.go:36). Bypass proof: a.GetID() returns N (raw positive share.ID, link_sharing.go:84) == user N's id → true. No a.(*LinkSharing) check on this branch (only IsAdmin at :50 has it, never reached). 3.…
Record
GHSA-32r8-5843-4qw2
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-639, CWE-843, CWE-863
Updated
2026-11-02
GitHub AdvisoriesGHSA-9xwc-vwww-qqmw 7.7

Duplicate Advisory: Vikunja: Link-share principal-type confusion enables cross-account team removal, bot takeover, and roster disclosure

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-32r8-5843-4qw2. This link is maintained to preserve external references.

Original Description

Vikunja through 2.4.0 contains a principal-type confusion vulnerability where LinkSharing principals with id N are treated as user principals with users.id == N at three permission checks lacking type guards. Attackers with a link-share JWT can remove victims from teams, enumerate and delete victim bot users, or read team rosters by exploiting id collisions in the autoincrement space.

Record
GHSA-9xwc-vwww-qqmw
CVSS 4.0
7.7 HighCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-639
Updated
2026-11-02
NVD 7.7

Vikunja through 2.4.0 contains a principal-type confusion vulnerability where LinkSharing principals with id N are treated as user principals with users.id == N at three permission checks lacking type guards. Attackers with a link-share JWT can remove victims from teams, enumerate and delete victim bot users, or read team rosters by exploiting id collisions in the autoincrement space.

Record
CVE-2026-76216
CVSS 4.0
7.7 HighCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-639
Updated
2026-11-02
OSV 7.7

Vikunja through 2.4.0 Principal-Type Confusion via LinkSharing

Vikunja through 2.4.0 contains a principal-type confusion vulnerability where LinkSharing principals with id N are treated as user principals with users.id == N at three permission checks lacking type guards. Attackers with a link-share JWT can remove victims from teams, enumerate and delete victim bot users, or read team rosters by exploiting id collisions in the autoincrement space.

Record
CVE-2026-76216
CVSS 4.0
7.7 HighCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-639
Updated
2026-11-02
OSVGHSA-32r8-5843-4qw2 7.5

Vikunja: Link-share principal-type confusion enables cross-account team removal, bot takeover, and roster disclosure

Summary

Vikunja's web.Auth interface (pkg/web/web.go, single method GetID() int64) is satisfied by BOTH *user.User and *models.LinkSharing. A link-share's GetID() returns the raw positive share.ID (pkg/models/link_sharing.go:83-85), which lives in the same positive autoincrement ID space as users.id. The safe negated form getUserID() = share.ID * -1 (link_sharing.go:126-128) exists but is NOT used at three permission sinks. As a result, a link-share principal with id N — which should have zero authority over teams or bot users — is treated as the user whose users.id == N at three permission checks that lack the a.(*LinkSharing) guard their sibling methods have. This is the same principal-type-confusion class as CVE-2026-68581 (GHSA-vvcv-vpph-h844), but at three code paths that advisory/fix never touched.

Root Cause

web.Auth is a one-method interface (GetID() int64). *LinkSharing.GetID() returns the raw positive share id. Three permission methods compare this raw id directly and omit the link-share type guard used elsewhere in the same files:

  1. TeamMember.CanDelete (pkg/models/team_members_permissions.go:31-40): the self-removal fast path if u.ID == a.GetID() { return true } (:36) executes before IsAdmin. IsAdmin (:48-51) is the ONLY place that rejects link shares (if _, is := a.(*LinkSharing); is { return false }, :50) — and it is never reached when the fast path returns true.
  2. BotUser.isOwner (pkg/models/bot_users_permissions.go:47-56): return u.BotOwnerID == a.GetID() (:55), used by CanRead/CanUpdate/CanDelete (:36-45). Unlike CanCreate (:27-30) which type-asserts a.(*user.User), these three paths have no principal guard.
  3. Team.CanRead (pkg/models/teams_permissions.go:68-78): matches membership on And("user_id = ?", a.GetID()) (:76) with no link-share guard, unlike sibling IsAdmin (:45-49, guard at :47).

Link-share JWTs reach these routes: SetupTokenMiddleware validates the signature only, GetAuthFromClaims returns *models.LinkSharing, and the /user//teams route groups add no link-share rejection. Link sharing is enabled by default (config.go ServiceEnableLinkSharing.setDefault(true)).

Impact

A link-share principal (obtainable from any public share link, or self-registered via a share on the attacker's own project) whose id N collides with a victim's users.id == N can, without being that user or any user:

  • Integrity (I:H): remove the victim from any team they belong to (DELETE /api/v1/teams/{T}/members/{username}) → revokes all project permissions the victim inherited through that team.
  • Availability/Integrity (A:H, I:H): enumerate the victim's bot users (GET /api/v1/user/bots → bot_owner_id = a.GetID()), then disable/rename or permanently delete them (DELETE /api/v1/user/bots/{id} → DeleteUser), destroying data owned solely by those bots.
  • Confidentiality (C:H): read the roster + metadata (name, description, full member list) of any team the colliding user belongs to (GET /api/v1/teams/{T}), plus read bot-user records via isOwner-gated reads.

Attack Chain

Sink 1 — TeamMember.CanDelete (integrity)

  1. Entry: POST /api/v1/shares/{hash}/auth → link-share JWT with id = N. Guard: JWT middleware — signature only. Bypass proof: GetAuthFromClaims returns *models.LinkSharing; no route-group link-share rejection on the /teams group.
  2. Action: DELETE /api/v1/teams/{T}/members/{usernameOfUserN} with the link-share bearer, targeting a team T (≥2 members) that user N belongs to. Guard: CanDelete → GetUserByUsername(tm.Username) returns user N, then u.ID == a.GetID() (team_members_permissions.go:36). Bypass proof: a.GetID() returns N (raw positive share.ID, link_sharing.go:84) == user N's id → true. No a.(*LinkSharing) check on this branch (only IsAdmin at :50 has it, never reached). 3.…
Record
GHSA-32r8-5843-4qw2
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-639, CWE-843, CWE-863
Updated
2026-11-02
OSVGHSA-9xwc-vwww-qqmw 7.7

Duplicate Advisory: Vikunja: Link-share principal-type confusion enables cross-account team removal, bot takeover, and roster disclosure

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-32r8-5843-4qw2. This link is maintained to preserve external references.

Original Description

Vikunja through 2.4.0 contains a principal-type confusion vulnerability where LinkSharing principals with id N are treated as user principals with users.id == N at three permission checks lacking type guards. Attackers with a link-share JWT can remove victims from teams, enumerate and delete victim bot users, or read team rosters by exploiting id collisions in the autoincrement space.

Record
GHSA-9xwc-vwww-qqmw
CVSS 4.0
7.7 HighCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-639
Updated
2026-11-02
OSVGO-2026-6711 No score

Vikunja: Link-share principal-type confusion enables cross-account team removal, bot takeover, and roster disclosure in code.vikunja.io/api

Vikunja: Link-share principal-type confusion enables cross-account team removal, bot takeover, and roster disclosure in code.vikunja.io/api

Record
GO-2026-6711
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
code.vikunja.io/api
Go
before 2.5.0
2.5.0
code.vikunja.io/api
Go
All versions None known

History

History
RecordedChangedSources
affected
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-76216 is a high vulnerability (CVSS 7.7) in Go-vikunja Vikunja, published August 19, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.36%, the 30th percentile. Fixed in code.vikunja.io/api 2.5.0.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open