CVE-2026-58438
Published:July 21, 2026
Updated:July 22, 2026
Details "RemoveDependency" in "routers/web/repo/issue_dependency.go" takes a "removeDependencyID" form parameter identifying the other issue by its global numeric ID, and fetches it with "issues_model.GetIssueByID(ctx, depID)" - no repository or permission check at all. It then calls "issues_model.RemoveIssueDependency(ctx, ctx.Doer, issue, dep, depType)" ("models/issues/dependency.go"), which deletes the dependency join row and then writes a comment referencing the removal, attributed to the calling user, onto the dependency record. The sibling function in the very same file, "AddDependency", does this correctly when the two issues are in different repos (which "ALLOW_CROSS_REPOSITORY_DEPENDENCIES", on by default, permits): if issue.RepoID != dep.RepoID { if !setting.Service.AllowCrossRepositoryDependencies { ... } depRepoPerm, err := access_model.GetDoerRepoPermission(ctx, dep.Repo, ctx.Doer) if !depRepoPerm.CanReadIssuesOrPulls(dep.IsPull) { return // you can't see this dependency } } "RemoveDependency" has no equivalent block at all - it goes straight from resolving "dep" by ID to deleting the link, regardless of which repo "dep" lives in or whether the caller can see it. I confirmed this same code is present in the current latest release, v1.26.4. PoC Prerequisites: an account with write access to issues on some repo "ownerA/repoA", and the global numeric issue ID of an issue in a private repo "repoB" that is (or was) legitimately dependency-linked to one of the attacker's issues in "repoA" (cross-repo dependencies are commonly used between related public/private repos, and "ALLOW_CROSS_REPOSITORY_DEPENDENCIES" defaults to enabled). curl -s -b "gitea_session=$ATTACKER_SESSION_COOKIE" -X POST --data-urlencode "removeDependencyID=<repoB_issue_global_id>" --data-urlencode "dependencyType=blockedBy" "https://TARGET_HOST/ownerA/repoA/issues/N/dependency/delete" Expected: the dependency link is deleted and a "removed dependency" comment authored by the attacker is added to the repoB issue, even though the attacker has no read access to repoB. Impact This is a cross-repository IDOR / broken access control issue. An attacker can tamper with issue-tracking state (dependency relationships) and inject an attacker-authored comment into a private repository they cannot otherwise read or write to, crossing a trust boundary the "add" path explicitly enforces. Impact is bounded - it requires an existing dependency link and discloses no repository content - but it is a genuine unauthorized-write primitive across a private-repo boundary. Fix Add the same cross-repo permission check used in "AddDependency" ("access_model.GetDoerRepoPermission(ctx, dep.Repo, ctx.Doer).CanReadIssuesOrPulls(dep.IsPull)") to "RemoveDependency" before allowing the deletion to proceed when "issue.RepoID != dep.RepoID". If possible, please apply for a CVE number when publishing. I would greatly appreciate it.
Affected Packages
https://github.com/go-gitea/gitea.git (GITHUB):
Affected version(s) >=v0.9.99 <v1.27.0Fix Suggestion:
Update to version v1.27.0gitea.dev (GO):
Affected version(s) >=v0.9.99 <v1.27.0Fix Suggestion:
Update to version v1.27.0Related Resources (3)
Do you need more information?
Contact UsCVSS v4
Base Score:
2.3
Attack Vector
NETWORK
Attack Complexity
HIGH
Attack Requirements
PRESENT
Privileges Required
LOW
User Interaction
NONE
Vulnerable System Confidentiality
NONE
Vulnerable System Integrity
LOW
Vulnerable System Availability
NONE
Subsequent System Confidentiality
NONE
Subsequent System Integrity
LOW
Subsequent System Availability
NONE
CVSS v3
Base Score:
3.5
Attack Vector
NETWORK
Attack Complexity
HIGH
Privileges Required
LOW
User Interaction
NONE
Scope
CHANGED
Confidentiality
NONE
Integrity
LOW
Availability
NONE
Weakness Type (CWE)
Missing Authorization