CVE-2026-54766 Overview
CVE-2026-54766 is a broken access control vulnerability [CWE-285] in Vikunja, an open-source self-hosted task management platform. The flaw affects versions from 0.21.0 until 2.4.0 in the project duplication logic at pkg/models/project_duplicate.go. An authenticated user who can read a source project can place its duplicate under any target parent project, even one they do not own. The permission check calls parent.CanCreate on an unhydrated Project struct instead of parent.CanWrite, bypassing the write permission enforcement. Attackers can inject content into other users' or teams' project hierarchies through PUT /api/v1/projects/{project}/duplicate.
Critical Impact
Authenticated attackers can inject attacker-owned project content into arbitrary user or team project hierarchies, corrupting workspace integrity and enabling limited data manipulation.
Affected Products
- Vikunja versions 0.21.0 through versions prior to 2.4.0
- Self-hosted Vikunja task management instances
- Vikunja API endpoint PUT /api/v1/projects/{project}/duplicate
Discovery Timeline
- 2026-08-28 - CVE-2026-54766 published to NVD
- 2026-08-28 - Last updated in NVD database
Technical Details for CVE-2026-54766
Vulnerability Analysis
The vulnerability resides in the ProjectDuplicate.CanCreate method within pkg/models/project_duplicate.go. When a user invokes the project duplication endpoint, Vikunja constructs a bare Project struct populated only with the body-supplied parent_project_id. The code then invokes parent.CanCreate(s, a) on this unhydrated object.
Because the struct is not hydrated from the database, CanCreate does not correctly evaluate write permission against the actual target parent project. The normal project creation path invokes CanWrite, which hydrates the project first and enforces the write permission check. The duplication path skips this enforcement, creating an authorization inconsistency between two functionally equivalent operations.
Root Cause
The root cause is an incorrect permission API selection combined with unhydrated object state. CanCreate on a bare struct evaluates against an empty project record rather than the target parent's actual ACL. The fix replaces this call with CanWrite, which hydrates the project record before evaluating permissions.
Attack Vector
An authenticated attacker with read access to any source project sends a PUT /api/v1/projects/{source}/duplicate request. The request body sets parent_project_id to a project owned by another user or team. The server accepts the request without verifying write access on the target parent, and the duplicated project is placed inside the victim's hierarchy.
return canRead, err
}
- // Parent project exists + user has write access to is (-> can create new projects)
+ // Placing the copy under a parent requires write access to that parent.
+ // CanWrite hydrates the project, unlike CanCreate on the bare struct.
parent := &Project{ID: pd.ParentProjectID}
- return parent.CanCreate(s, a)
+ return parent.CanWrite(s, a)
}
// Create duplicates a project
Source: GitHub Commit d911caa
Detection Methods for CVE-2026-54766
Indicators of Compromise
- Unexpected child projects appearing beneath user or team-owned parent projects
- PUT /api/v1/projects/{project}/duplicate requests where the request body parent_project_id references a project the caller does not own
- Audit log entries showing project duplication where the source and target parent belong to different owners
Detection Strategies
- Review Vikunja access logs for calls to the duplicate endpoint and correlate the requesting user against the target parent_project_id owner
- Query the Vikunja database to identify projects whose creator differs from the owner of the parent project in the hierarchy
- Enable API request logging on the reverse proxy fronting Vikunja to capture request bodies for forensic analysis
Monitoring Recommendations
- Alert on high-volume duplication requests from a single authenticated user
- Monitor for project tree modifications that cross ownership boundaries
- Track HTTP PUT calls to /api/v1/projects/*/duplicate and baseline normal usage
How to Mitigate CVE-2026-54766
Immediate Actions Required
- Upgrade Vikunja to version 2.4.0 or later, which enforces parent.CanWrite on the target parent project
- Audit existing project hierarchies for cross-owner duplicates created during the vulnerable window
- Rotate any shared credentials or tokens used by low-trust authenticated accounts on affected instances
Patch Information
The issue is fixed in Vikunja version 2.4.0. The fix, tracked in GitHub Pull Request #3239 and committed in d911caa, replaces parent.CanCreate with parent.CanWrite inside ProjectDuplicate.CanCreate. Full release notes are available in the GitHub Release v2.4.0 and details in the GitHub Security Advisory GHSA-f27p-pw2p-9pr4.
Workarounds
- Restrict access to the PUT /api/v1/projects/{project}/duplicate endpoint at the reverse proxy layer until upgrade is complete
- Limit account creation and reduce the number of authenticated users with read access to sensitive projects
- Monitor project hierarchies for unauthorized child projects and remove them as they are discovered
# Example nginx rule to block the duplicate endpoint until patched
location ~ ^/api/v1/projects/[0-9]+/duplicate$ {
if ($request_method = PUT) {
return 403;
}
proxy_pass http://vikunja_backend;
}
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

