# Vikunja vulnerable to Privilege Escalation via Project Reparenting

Vikunja only checked Write on the new parent when reparenting a project, so a Write-shared collaborator could move it under their own tree and gain Admin.

- Payout: Research
- Severity: high
- Program: Vikunja
- Found by: adrgs, aisafe-bot
- Disclosed: 2026-04-10
- CVE: CVE-2026-35595
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-2vq4-854f-5c72
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-2vq4-854f-5c72
- Tags: area:web domain:api domain:web impact:data-leak impact:integrity kind:research platform:ghsa sev:high tech:go technique:source-review vuln:access-control vuln:auth-bypass vuln:privilege-escalation

**Target:** Vikunja REST API project update endpoint (/api/v1/projects/{id})
**Root cause:** The parent_project_id change handler only requires CanWrite on the new parent, but permissions are computed by a recursive CTE walking the hierarchy, so ownership of the new parent resolves as Admin on the moved project.
**Steps:**
1. Victim creates parent project (id=3) and child project (id=4) under it
2. Victim shares parent with attacker at Write (permission=1); attacker inherits Write on child
3. Attacker creates own root project (id=5)
4. Attacker confirms `DELETE /api/v1/projects/4` returns 403
5. Attacker sends `POST /api/v1/projects/4 {"title":"Secret Child","parent_project_id":5}` -> 200
6. Attacker sends `DELETE /api/v1/projects/4` -> 200; victim gets 404
**How found:** Code reading of the CanUpdate check at pkg/models/project_permissions.go:139-148 revealed only CanWrite was enforced on the new parent, while the permission CTE walks the hierarchy — so reparenting rewrites the inheritance chain.
**Exploitation:** Attacker with inherited Write on a child project reparents it under a project they own via one API call; the recursive permission CTE then resolves Admin on the moved project, allowing deletion, share management and removal of other users' access.
**Escalation:** Inherited Write on a child becomes Admin over that project and its contents by changing the inheritance chain.
**Insight:** When permissions are inherited via a recursive hierarchy walk, any operation that mutates the hierarchy edge (reparent, move, transfer) is a privilege boundary — check the actor's rights on both the old and new parent, not just Write on the destination.

## Proof of concept (copied exactly from the original report)

**Reparent request then delete after escalation**

```
6. attacker sends: POST /api/v1/projects/4 {"title":"Secret Child","parent_project_id":5}
   -> 200 OK (reparenting succeeds, only requires Write)
7. attacker sends: DELETE /api/v1/projects/4 -> 200 OK
   -> Project deleted. victim gets 404.
```

