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.
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.
An authenticated user with admin access to any project can:
DELETE /api/v1/projects/{projectB_id}/shares/{X}WHERE id = X — deleting User A's link shareChange 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.
{
"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"
}