A AegiFlow
LOWCVSS 2.7

CVE-2026-58445

Gitea: Cross-repository label-ID enumeration oracle via unscoped DeleteIssueLabel API

Published
2026-07-21
Modified
2026-07-21
Aliases
GHSA-pgqf-926r-548m
Sources
github-advisory

Summary

## Summary The API endpoint `DELETE /repos/{owner}/{repo}/issues/{index}/labels/{id}` loads the label by ID with a **global, unscoped** lookup and never verifies the label belongs to the URL's repository (or its owning organization). Because the response status differs by whether the label ID exists **anywhere on the instance** (204) versus not (422), an authenticated user can use the endpoint as a **cross-repository label-ID existence / enumeration oracle**, including for labels in repositories and organizations they cannot access. ## Severity - The leaked information is minimal (existence/count of label IDs instance-wide); **no label name, color, or owning repository is disclosed, and no cross-repository write occurs.** ## Affected / patched versions - **Affected:** through **1.26.3** (latest at time of report). - **Patched:** none yet. ## Details `DeleteIssueLabel` resolves the label with a global loader and never checks its scope: ```go // routers/api/v1/repo/issue_label.go (DeleteIssueLabel) label, err := issues_model.GetLabelByID(ctx, ctx.PathParamInt64("id")) // global, unscoped ``` `GetLabelByID` (`models/issues/label.go`) is `e.ID(labelID).Get(l)` with **no** `repo_id` / `org_id` filter. The handler never verifies `label.RepoID == ctx.Repo.Repository.ID` (nor the org-label equivalent), and the downstream `issue_service.RemoveLabel` (`services/issue/label.go`) only re-checks the doer's write permission on the **issue's own** repository — never that the label belongs to it. Every sibling label handler is correctly scoped — `GetLabel` / `EditLabel` / `DeleteLabel` (repo and org) use `GetLabelInRepoByID` / `GetLabelInOrgByID` and return 404 for a foreign ID. `DeleteIssueLabel` is the only outlier. **Why it is only an oracle:** `deleteIssueLabel` (`models/issues/issue_label.go`) deletes the `issue_label` row keyed by `(issue.ID, label.ID)`. For a foreign label, no such row exists → the function returns early **before** any mutation or comment creation. So there is no cross-repo write and no leak of the label's name. But the HTTP status differs: - label ID exists anywhere on the instance (incl. private repos/orgs) → **204 No Content** - label ID does not exist → **422** (`ErrLabelNotExist`) Label IDs are sequential auto-increment, so this enumerates the instance-wide label population and probes existence of specific IDs across tenant boundaries. ## Proof of Concept Verified end-to-end on a build of the `v1.26.3` tag. - `alice` (private repo `alice/secret`) creates a label → internal id **1**. - Attacker `bob` (separate user; public repo `bob/pub` with issue #1; **no access** to `alice/secret`) holds a token with `write:issue` on his own repo. ```text bob DELETE /api/v1/repos/bob/pub/issues/1/labels/1 -> HTTP 204 (alice's PRIVATE label id exists) bob DELETE /api/v1/repos/bob/pub/issues/1/labels/99999999 -> HTTP 422 (no such label) ``` Differing only by the label ID: `204` vs `422` distinguishes "label ID exists" from "does not exist." `bob` has zero rights to `alice/secret` but can still learn label id 1 exists. (Alice's label is untouched — no write.) Reproduction steps: 1. Create two users `alice`, `bob`. As `alice`, create a private repo and a label on it (note the label `id` from the API response). 2. As `bob`, create any repo with an issue, and a token with `write:issue`. 3. `curl -u bob:$T -X DELETE https:// /api/v1/repos/bob/pub/issues/1/labels/ ` → **204**. 4. `curl -u bob:$T -X DELETE https:// /api/v1/repos/bob/pub/issues/1/labels/99999999` → **422**. 5. The differing status across an ID `bob` cannot otherwise see is the oracle. ## Impact Cross-tenant authorization-key bypass producing a label-ID existence/enumeration oracle: an authenticated user can determine whether arbitrary label IDs (including in private repositories and organizations they cannot access) exist, and enumerate the instance-wide label population. ## Remediation Scope the l

Affected packages

EcosystemPackageAffected versionsFixed versions
Gocode.gitea.io/gitea1.27.0

Remediation: Upgrade to 1.27.0 or later.

References

Includes data from the GitHub Advisory Database, licensed under CC-BY 4.0.

CVE® is a registered trademark of The MITRE Corporation. CVE content reproduced under the CVE Terms of Use; copyright designation © MITRE.