GHSA-F95F-77JX-FCJC
Vulnerability from github – Published: 2026-03-25 21:21 – Updated: 2026-03-25 21:21Summary
The DELETE /api/v1/projects/:project/shares/:share endpoint does not verify that the link share belongs to the project specified in the URL. An attacker with admin access to any project can delete link shares from other projects by providing their own project ID combined with the target share ID.
Details
The permission check in canDoLinkShare (pkg/models/link_sharing_permissions.go:53-70) validates admin access on the project from the :project URL parameter. However, the Delete method at pkg/models/link_sharing.go:305 queries only WHERE id = ? using the share ID, without verifying it belongs to the URL-specified project:
func (share *LinkSharing) Delete(s *xorm.Session, _ web.Auth) (err error) {
_, err = s.Where("id = ?", share.ID).Delete(share)
return
}
This is the same vulnerability class as GHSA-jfmm-mjcp-8wq2 (task attachment IDOR) and the fixed GHSA-mr3j-p26x-72x4 (task comment IDOR).
Additionally, ReadOne at line 203 has the same pattern (WHERE id = ? only), though it is not currently exploitable because CanRead fails first due to an unrelated issue with the hash parameter binding.
Impact
An authenticated user with admin access to any project can: - Delete link shares belonging to any other project in the system - Disrupt collaboration by removing shared access links - Link share IDs are sequential integers, making enumeration trivial
Reproduction
- User A creates Project A and a link share on it (share ID = X)
- User B creates Project B (gaining admin access)
- User B calls
DELETE /api/v1/projects/{projectB_id}/shares/{X} - The permission check passes (User B is admin on Project B)
- The delete executes
WHERE id = X— deleting User A's link share
Recommended Fix
Change Delete at pkg/models/link_sharing.go:305 to:
_, err = s.Where("id = ? AND project_id = ?", share.ID, share.ProjectID).Delete(share)
Also fix ReadOne at line 203 as defense in depth.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "code.vikunja.io/api"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.2.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-33700"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-25T21:21:20Z",
"nvd_published_at": "2026-03-24T16:16:35Z",
"severity": "MODERATE"
},
"details": "## Summary\n\nThe `DELETE /api/v1/projects/:project/shares/:share` endpoint does not verify that the link share belongs to the project specified in the URL. An attacker with admin access to any project can delete link shares from other projects by providing their own project ID combined with the target share ID.\n\n## Details\n\nThe permission check in `canDoLinkShare` (`pkg/models/link_sharing_permissions.go:53-70`) validates admin access on the project from the `:project` URL parameter. However, the `Delete` method at `pkg/models/link_sharing.go:305` queries only `WHERE id = ?` using the share ID, without verifying it belongs to the URL-specified project:\n\n```go\nfunc (share *LinkSharing) Delete(s *xorm.Session, _ web.Auth) (err error) {\n _, err = s.Where(\"id = ?\", share.ID).Delete(share)\n return\n}\n```\n\nThis is the same vulnerability class as GHSA-jfmm-mjcp-8wq2 (task attachment IDOR) and the fixed GHSA-mr3j-p26x-72x4 (task comment IDOR).\n\nAdditionally, `ReadOne` at line 203 has the same pattern (`WHERE id = ?` only), though it is not currently exploitable because `CanRead` fails first due to an unrelated issue with the hash parameter binding.\n\n## Impact\n\nAn authenticated user with admin access to any project can:\n- Delete link shares belonging to any other project in the system\n- Disrupt collaboration by removing shared access links\n- Link share IDs are sequential integers, making enumeration trivial\n\n## Reproduction\n\n1. User A creates Project A and a link share on it (share ID = X)\n2. User B creates Project B (gaining admin access)\n3. User B calls `DELETE /api/v1/projects/{projectB_id}/shares/{X}`\n4. The permission check passes (User B is admin on Project B)\n5. The delete executes `WHERE id = X` \u2014 deleting User A\u0027s link share\n\n## Recommended Fix\n\nChange `Delete` at `pkg/models/link_sharing.go:305` to:\n\n```go\n_, err = s.Where(\"id = ? AND project_id = ?\", share.ID, share.ProjectID).Delete(share)\n```\n\nAlso fix `ReadOne` at line 203 as defense in depth.",
"id": "GHSA-f95f-77jx-fcjc",
"modified": "2026-03-25T21:21:20Z",
"published": "2026-03-25T21:21:20Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/go-vikunja/vikunja/security/advisories/GHSA-f95f-77jx-fcjc"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33700"
},
{
"type": "PACKAGE",
"url": "https://github.com/go-vikunja/vikunja"
},
{
"type": "WEB",
"url": "https://vikunja.io/changelog/vikunja-v2.2.2-was-released"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Vikunja has a Link Share Delete IDOR \u2014 Missing Project Ownership Check Allows Cross-Project Link Share Deletion"
}
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.