Every CVE Search/ Get API key

CVE-2026-91985

Vikunja before 2.6.0 Privilege Escalation via Link Share Hash

8.7 HighFix available

Vikunja before 2.6.0 fails to properly restrict access to the link-share hash field in single-share read endpoints, allowing read-only members to obtain the share's secret credential. Attackers can exchange the disclosed hash for a link-share JWT at the share's permission level to escalate privileges and perform unauthorized writes or administrative actions.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
None
Availability
None

Exploit likelihood

0.43%Up 0.1 points since Sep 16, 2026
90%50%10%1%

What each source reports

CVE List Score used 8.7

Vikunja before 2.6.0 Privilege Escalation via Link Share Hash

Vikunja before 2.6.0 fails to properly restrict access to the link-share hash field in single-share read endpoints, allowing read-only members to obtain the share's secret credential. Attackers can exchange the disclosed hash for a link-share JWT at the share's permission level to escalate privileges and perform unauthorized writes or administrative actions.

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

Vikunja before 2.6.0 fails to properly restrict access to the link-share hash field in single-share read endpoints, allowing read-only members to obtain the share's secret credential. Attackers can exchange the disclosed hash for a link-share JWT at the share's permission level to escalate privileges and perform unauthorized writes or administrative actions.

Record
EUVD-2026-78656
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-37rx-7pj5-p885 8.7

Duplicate Advisory: Vikunja: Read-only project members can obtain any link share's access hash via the single-share read endpoint (v1 and v2) and escalate to the share's permission level

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-qfwc-vx6f-3g6g. This link is maintained to preserve external references.

Original Description

Vikunja before 2.6.0 fails to properly restrict access to the link-share hash field in single-share read endpoints, allowing read-only members to obtain the share's secret credential. Attackers can exchange the disclosed hash for a link-share JWT at the share's permission level to escalate privileges and perform unauthorized writes or administrative actions.

Record
GHSA-37rx-7pj5-p885
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/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:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
GitHub AdvisoriesGHSA-qfwc-vx6f-3g6g No score

Vikunja: Read-only project members can obtain any link share's access hash via the single-share read endpoint (v1 and v2) and escalate to the share's permission level

Summary

A user who has only read permission on a project can call the single link-share read endpoint and receive the share's hash field — the secret credential that the anonymous POST /shares/{share}/auth endpoint exchanges for a link-share JWT carrying the share's permission (read / read-write / admin). A read-only member can therefore mint a write- or admin-level token for the project and perform writes they are not entitled to, while their own user token is correctly refused. This is the remaining variant of the link-share hash disclosure class: GHSA-8hp8-9fhr-pfm9 fixed the list endpoint (ReadAll now requires project admin) but the single-read endpoint's gate was never aligned. Verified on Vikunja 2.5.0; the weak gate has existed since the endpoint, so earlier versions are likely affected too.

Details

Affected endpoints (both verified with a complete chain):

  • v1: GET /api/v1/projects/{project}/shares/{share}
  • v2: GET /api/v2/projects/{project}/shares/{share}

Permission gate: LinkSharing.CanRead (pkg/models/link_sharing_permissions.go) delegates to project.CanRead(s, a) — i.e. any user with read access to the project passes. The response serializes the hash field (pkg/models/link_sharing.go, field tag json:"hash"), which is the share's bearer credential. The share password field is correctly cleared before returning, but the hash is not restricted.

Inconsistent with the sibling list endpoint GET /projects/{project}/shares (LinkSharing.ReadAll, pkg/models/link_sharing.go:243-256), which requires project.IsAdmin — the protection level the project chose when the class was fixed for the list endpoint in 2.3.0 (GHSA-8hp8). The v1 and v2 APIs share the same model-level gate (the v2 handler.DoReadOne wrappers call the same CanRead), so both surfaces are affected.

Impact chain: hash -> POST /api/v1/shares/{hash}/auth (unauthenticated by design) -> link-share JWT at the share's permission level -> full API access at that level for that project.

Mitigating factors: the attacker must already be a member of the project at read level; password-protected shares (sharing_type=2) still require the password at the auth step; share IDs are small sequential integers and enumerable by members.

PoC

Steps below use two accounts: the owner (token $OWNER) and an attacker who has been granted read-only access to the project (token $READER). All requests were executed against a local Vikunja 2.5.0 instance.

  1. Owner creates a private project and a read-write link share (permission=1):
curl -X PUT "$BASE/api/v1/projects" -H "Authorization: Bearer $OWNER" \
  -H 'Content-Type: application/json' -d '{"title":"poc"}'
# -> {"id":123,...}

curl -X PUT "$BASE/api/v1/projects/123/shares" -H "Authorization: Bearer $OWNER" \
  -H 'Content-Type: application/json' -d '{"name":"poc","permission":1}'
# -> {"id":7,"hash":"<SECRET_HASH>",...}
  1. Owner adds the attacker as a read-only member (permission=0):
curl -X PUT "$BASE/api/v1/projects/123/users" -H "Authorization: Bearer $OWNER" \
  -H 'Content-Type: application/json' -d '{"username":"attacker","permission":0}'
  1. Attacker reads the single share — the weak gate — and receives the hash (this is the disclosure; the list endpoint would correctly return 403 here):
curl "$BASE/api/v1/projects/123/shares/7" -H "Authorization: Bearer $READER"
# -> 200 {"id":7,"hash":"<SECRET_HASH>","permission":1,...}
# v2 twin behaves identically:
curl "$BASE/api/v2/projects/123/shares/7" -H "Authorization: Bearer $READER"
# -> 200 {"hash":"<SECRET_HASH>",...}
  1. Attacker exchanges the hash for a link-share JWT (no authentication required):
curl -X POST "$BASE/api/v1/shares/<SECRET_HASH>/auth" \
  -H 'Content-Type: application/json' -d '{}'
# -> 200 {"token":"<LINK_JWT>",...}
  1. Negative control — the attacker's own user token cannot write to the project:
curl -X PUT "$BASE/api/v1/projects/123/tasks" -H…
Record
GHSA-qfwc-vx6f-3g6g
Weakness
CWE-200, CWE-639, CWE-862
Updated
2026-11-02
NVD 8.7

Vikunja before 2.6.0 fails to properly restrict access to the link-share hash field in single-share read endpoints, allowing read-only members to obtain the share's secret credential. Attackers can exchange the disclosed hash for a link-share JWT at the share's permission level to escalate privileges and perform unauthorized writes or administrative actions.

Record
CVE-2026-91985
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/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:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
OSV 8.7

Vikunja before 2.6.0 Privilege Escalation via Link Share Hash

Vikunja before 2.6.0 fails to properly restrict access to the link-share hash field in single-share read endpoints, allowing read-only members to obtain the share's secret credential. Attackers can exchange the disclosed hash for a link-share JWT at the share's permission level to escalate privileges and perform unauthorized writes or administrative actions.

Record
CVE-2026-91985
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Weakness
CWE-200
Updated
2026-11-02
OSVGHSA-37rx-7pj5-p885 8.7

Duplicate Advisory: Vikunja: Read-only project members can obtain any link share's access hash via the single-share read endpoint (v1 and v2) and escalate to the share's permission level

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-qfwc-vx6f-3g6g. This link is maintained to preserve external references.

Original Description

Vikunja before 2.6.0 fails to properly restrict access to the link-share hash field in single-share read endpoints, allowing read-only members to obtain the share's secret credential. Attackers can exchange the disclosed hash for a link-share JWT at the share's permission level to escalate privileges and perform unauthorized writes or administrative actions.

Record
GHSA-37rx-7pj5-p885
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/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:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-200
Updated
2026-11-02
OSVGHSA-qfwc-vx6f-3g6g No score

Vikunja: Read-only project members can obtain any link share's access hash via the single-share read endpoint (v1 and v2) and escalate to the share's permission level

Summary

A user who has only read permission on a project can call the single link-share read endpoint and receive the share's hash field — the secret credential that the anonymous POST /shares/{share}/auth endpoint exchanges for a link-share JWT carrying the share's permission (read / read-write / admin). A read-only member can therefore mint a write- or admin-level token for the project and perform writes they are not entitled to, while their own user token is correctly refused. This is the remaining variant of the link-share hash disclosure class: GHSA-8hp8-9fhr-pfm9 fixed the list endpoint (ReadAll now requires project admin) but the single-read endpoint's gate was never aligned. Verified on Vikunja 2.5.0; the weak gate has existed since the endpoint, so earlier versions are likely affected too.

Details

Affected endpoints (both verified with a complete chain):

  • v1: GET /api/v1/projects/{project}/shares/{share}
  • v2: GET /api/v2/projects/{project}/shares/{share}

Permission gate: LinkSharing.CanRead (pkg/models/link_sharing_permissions.go) delegates to project.CanRead(s, a) — i.e. any user with read access to the project passes. The response serializes the hash field (pkg/models/link_sharing.go, field tag json:"hash"), which is the share's bearer credential. The share password field is correctly cleared before returning, but the hash is not restricted.

Inconsistent with the sibling list endpoint GET /projects/{project}/shares (LinkSharing.ReadAll, pkg/models/link_sharing.go:243-256), which requires project.IsAdmin — the protection level the project chose when the class was fixed for the list endpoint in 2.3.0 (GHSA-8hp8). The v1 and v2 APIs share the same model-level gate (the v2 handler.DoReadOne wrappers call the same CanRead), so both surfaces are affected.

Impact chain: hash -> POST /api/v1/shares/{hash}/auth (unauthenticated by design) -> link-share JWT at the share's permission level -> full API access at that level for that project.

Mitigating factors: the attacker must already be a member of the project at read level; password-protected shares (sharing_type=2) still require the password at the auth step; share IDs are small sequential integers and enumerable by members.

PoC

Steps below use two accounts: the owner (token $OWNER) and an attacker who has been granted read-only access to the project (token $READER). All requests were executed against a local Vikunja 2.5.0 instance.

  1. Owner creates a private project and a read-write link share (permission=1):
curl -X PUT "$BASE/api/v1/projects" -H "Authorization: Bearer $OWNER" \
  -H 'Content-Type: application/json' -d '{"title":"poc"}'
# -> {"id":123,...}

curl -X PUT "$BASE/api/v1/projects/123/shares" -H "Authorization: Bearer $OWNER" \
  -H 'Content-Type: application/json' -d '{"name":"poc","permission":1}'
# -> {"id":7,"hash":"<SECRET_HASH>",...}
  1. Owner adds the attacker as a read-only member (permission=0):
curl -X PUT "$BASE/api/v1/projects/123/users" -H "Authorization: Bearer $OWNER" \
  -H 'Content-Type: application/json' -d '{"username":"attacker","permission":0}'
  1. Attacker reads the single share — the weak gate — and receives the hash (this is the disclosure; the list endpoint would correctly return 403 here):
curl "$BASE/api/v1/projects/123/shares/7" -H "Authorization: Bearer $READER"
# -> 200 {"id":7,"hash":"<SECRET_HASH>","permission":1,...}
# v2 twin behaves identically:
curl "$BASE/api/v2/projects/123/shares/7" -H "Authorization: Bearer $READER"
# -> 200 {"hash":"<SECRET_HASH>",...}
  1. Attacker exchanges the hash for a link-share JWT (no authentication required):
curl -X POST "$BASE/api/v1/shares/<SECRET_HASH>/auth" \
  -H 'Content-Type: application/json' -d '{}'
# -> 200 {"token":"<LINK_JWT>",...}
  1. Negative control — the attacker's own user token cannot write to the project:
curl -X PUT "$BASE/api/v1/projects/123/tasks" -H…
Record
GHSA-qfwc-vx6f-3g6g
Weakness
CWE-200, CWE-639, CWE-862
Updated
2026-11-02
OSVGO-2026-6747 No score

Vikunja: Read-only project members can obtain any link share's access hash via the single-share read endpoint (v1 and v2) and escalate to the share's permission level in code.vikunja.io/api

Vikunja: Read-only project members can obtain any link share's access hash via the single-share read endpoint (v1 and v2) and escalate to the share's permission level in code.vikunja.io/api.

NOTE: The source advisory for this report contains additional versions that could not be automatically mapped to standard Go module versions.

(If this is causing false-positive reports from vulnerability scanners, please suggest an edit to the report.)

The additional affected modules and versions are: code.vikunja.io/api before v2.6.0.

Record
GO-2026-6747
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
code.vikunja.io/api
Go
through 2.5.0
2.6.0
code.vikunja.io/api
Go
before 2.6.0
2.6.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-91985 is a high vulnerability (CVSS 8.7) in Go-vikunja Vikunja, published September 15, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.43%, the 37th percentile. Fixed in code.vikunja.io/api 2.6.0.

References

Show 4 moreShow less
This page doesn't list everything

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

MoveEnter Open