Oct 10, 2026·5 min read·2 visits
In Vikunja versions prior to 2.6.0, deleting a task relation only verifies access permissions for the source task. An authenticated user can unlink tasks in unauthorized or private projects.
An authorization bypass vulnerability in Vikunja versions prior to v2.6.0 permits authenticated users to delete relationships between tasks across project boundaries without requiring read or write authorization for the target related task.
Vikunja is an open-source, self-hosted task management application written in Go. The platform allows users to structure tasks into projects, set access control permissions per project, and construct relationships between tasks (such as subtasks, dependencies, or related references). Because tasks residing in different projects can be linked together, task relations often cross organizational and permission boundaries.
During relation management operations, the system must enforce dual-endpoint access control. When establishing or breaking a relationship between two entities, authorization checks must confirm that the requesting principal possesses sufficient rights on both target objects. In versions of Vikunja prior to v2.6.0, the handler responsible for relation deletion enforced authorization checks on only one side of the relationship.
An attacker with legitimate access to a single task (Task A) can delete any existing relationship pointing to or from a target task (Task B), even if Task B belongs to a restricted project to which the attacker has no read or write privileges. This issue represents a failure of access control mechanisms defined under CWE-862 (Missing Authorization) and CWE-284 (Improper Access Control).
The root cause stems from incomplete permission validation in the task relation deletion service layer. In Vikunja, task relations are represented as directional or bidirectional links stored in the relational database, indexed by relation identifiers or task identifier pairs.
When a client submits an HTTP DELETE request to sever a relationship between Task A and Task B, the API controller invokes authorization helpers to confirm that the user has permission to edit Task A. Upon successful validation of Task A, the service immediately executed the deletion query against the underlying database table without evaluating the user's permissions regarding Task B.
The logic incorrectly assumed that owning or having write permissions on one end of a relation automatically grants complete management authority over the relation as a whole. Consequently, cross-project relations could be modified unilaterally by any participant who had permission over at least one connected task, violating project isolation boundaries.
The remediation was introduced in pull request #3688 and committed via SHA 077dc4de79ce6f1ab59215a2c7bf9b30423685f2. The fix updates the authorization verification function invoked during task relation deletion.
Prior to the patch, the function performed a single permission evaluation against Task A. The patched version introduces an explicit check against Task B prior to executing the database removal statement. If the user lacks read access to Task B, the API yields an HTTP 403 Forbidden or HTTP 404 Not Found error, halting execution.
// Vulnerable logic pattern:
func (s *TaskRelationService) Delete(ctx context.Context, rel *models.TaskRelation) error {
// Only validated access to the primary task
if err := s.canWriteTask(ctx, rel.TaskID); err != nil {
return err
}
return s.repo.DeleteRelation(ctx, rel.ID)
}
// Patched logic pattern (v2.6.0):
func (s *TaskRelationService) Delete(ctx context.Context, rel *models.TaskRelation) error {
if err := s.canWriteTask(ctx, rel.TaskID); err != nil {
return err
}
// Added permission check for the related task
if err := s.canReadTask(ctx, rel.OtherTaskID); err != nil {
return err
}
return s.repo.DeleteRelation(ctx, rel.ID)
}The fix is complete for this specific endpoint. By enforcing that the user must at least have read access to the secondary task before modifying its relations, the authorization bypass is fully blocked.
Exploitation requires valid user credentials on a Vikunja instance. The attacker must control at least one project where they have permission to view or edit tasks.
Task A) in their accessible project.Task A and a target task (Task B) in another project, or identifies an existing relation between Task A and Task B created previously or by another user.Task B) resides in a project where the attacker has no permission rights.Task A and Task B.Task A, ignores the lack of permissions for Task B, and removes the relation record.As a result, project workflows, dependency chains, and tracking links established by members of restricted projects can be disrupted by unauthorized users without triggering audit flags for Task B.
This vulnerability affects data integrity and relation metadata consistency across projects within Vikunja. The impact is classified as localized data tampering (Integrity: Low) without direct confidentiality loss or unauthorized remote code execution.
Attacker capabilities are constrained to removing task relationships. Attackers cannot read the contents of private tasks or modify task titles, descriptions, or assignees in restricted projects solely through this bug. However, removing critical dependency links (such as 'blocking' relationships) can cause disruption to operational tracking and project management workflows.
The vulnerability is scored as CVSS 5.3 (Medium) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N. No automated exploitation attempts or public weaponized exploit code have been recorded in threat intelligence feeds.
The primary remediation strategy is upgrading the Vikunja instance to version v2.6.0 or later. This release incorporates the mandatory dual-endpoint authorization check for relation deletion API endpoints.
No permanent configuration settings or environment toggles can remediate the underlying flaw in affected versions (< 2.6.0). Organizations unable to update immediately should review API access logs for anomalous DELETE requests targeting /tasks/{id}/relations/{relation_id}.
After upgrading, administrators can audit project task relations using database queries to verify that dependency structures remain intact and consistent.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Vikunja Vikunja | < 2.6.0 | 2.6.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-862 (Missing Authorization) |
| CVSS v3.1 Score | 5.3 (Medium) |
| Attack Vector | Network (Unauthenticated: No, Authenticated: Yes) |
| Impact | Integrity (Unauthorized relation removal) |
| Exploit Status | None / No public weaponized exploit |
| CISA KEV Status | Not Listed |
The software does not perform an authorization check when an actor attempts to access a resource or perform an action.
An information disclosure vulnerability in Vikunja allows authenticated users with read access to a task to expose private email addresses of assigned users through the API task assignees endpoint due to an unmasked database query.
A path traversal vulnerability in Shiny for Python (posit-dev/py-shiny) versions 1.4.0 through 1.6.3 allows unauthenticated remote attackers to read arbitrary files and traverse directories via crafted _state_id_ query parameters.
A Stored Cross-Site Scripting vulnerability in @tinacms/web-components prior to version 0.2.1 allows low-privileged content authors to execute arbitrary JavaScript code in the context of website visitors via unsanitized URL attributes in custom Markdown rendering components.
A critical origin validation flaw in TinaCMS admin preview allows unauthenticated attackers to bypass cross-origin postMessage checks and execute unauthorized GraphQL queries and mutations under an authenticated editor's context.
@tinacms/cli prior to version 3.0.0 dynamically constructs client source files using string interpolation without properly sanitizing runtime configuration variables. An attacker with permissions to create a branch or pull request can inject arbitrary JavaScript statements via a crafted Git ref name, leading to execution during automated build processes.
Nginx UI versions 2.2.0 through 2.5.10 fail to properly configure Gin framework trusted proxies when deployed behind a reverse proxy. This causes all incoming HTTP requests to be attributed to the loopback IP (127.0.0.1), enabling IP allowlist bypass and global authentication lockouts.