Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessAuthenticate as any Gitea user
-
DeliveryObtain write:issue token on attacker-controlled repository
-
ExploitSend DELETE /api/v1/repos/{own-repo}/issues/{id}/labels/{target_id}
-
ExecutionObserve 204 (label exists anywhere on instance) vs. 422 (does not exist)
-
PersistIterate sequential label IDs
-
ImpactEnumerate instance-wide label population across tenant boundaries
Vulnerability Assessment
| Weakness |
CWE
ASVS 5.0
V6 - Authentication Timing-safe comparisons
|
| Exploitation Conditions | The attacker must be an authenticated Gitea user holding write:issue permission on at least one repository they control, and must have network access to the Gitea REST API. No special server configuration, non-default feature, or administrative privilege is required - the vulnerability is present in the default API behavior of all Gitea instances through v1.26.3. Exploitation is bounded by what the oracle reveals: only label ID existence (boolean, per ID) is leaked; label names, colors, repository names, content, and owning organization are not disclosed, and no cross-repository write occurs. Unauthenticated users or users with no repository (and thus no write:issue scope) cannot exploit this. The practical constraint is that automated sequential scanning over a large ID space would generate significant API log entries, making large-scale enumeration detectable. |
| Impact | The provided CVSS 3.1 base score of 2.7 (AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N) understates real-world exploitability: the vendor assigned PR:H, but any regular authenticated Gitea user holding write:issue on any repository they own - a standard, user-level permission - can trigger the oracle without administrative access, suggesting PR:L is more appropriate (raising the base score to approximately 4.3). The impact remains narrow: only label ID existence is leaked, with no names, colors, repository names, or content exposed, and no write side-effects. The vulnerability is absent from the CISA KEV catalog, and EPSS data is not provided; given the authentication prerequisite and minimal leaked information, widespread exploitation is unlikely. The primary real-world risk is on multi-tenant public Gitea instances where untrusted users can probe the label ID space of private repositories belonging to other tenants. Single-tenant or closed-registration instances face negligible incremental exposure. The existence of a researcher-verified PoC means exploit difficulty is essentially zero for any valid Gitea account holder. |
| Exploit ScenarioDerived | A working proof of concept was verified against Gitea v1.26.3 by the reporter. An authenticated attacker (bob) with write:issue on any repository they control sends DELETE /api/v1/repos/bob/pub/issues/1/labels/{target_id} with sequential label IDs; a 204 response confirms the label ID exists somewhere on the instance (including in alice's private repository), while a 422 confirms it does not. Iterating IDs from 1 upward enumerates the entire instance label population across all tenant boundaries without any access to the target repositories. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Jul 21, 2026
Cross-repository label-ID enumeration oracle in Gitea through v1.26.3 allows any authenticated user with write:issue permission on any repository to probe label ID existence across all repositories and organizations on the instance - including private ones they cannot access. The flaw arises because the DELETE /repos/{owner}/{repo}/issues/{index}/labels/{id} API handler performs a global, unscoped label lookup and leaks existence via differential HTTP status codes (204 vs. 422). No label names, colors, repository associations, or content are disclosed, and no cross-repository writes occur; however, a working proof of concept was verified against v1.26.3 and a fix is available in v1.27.0. No public exploit identified at time of analysis beyond the verified PoC in the advisory.
RemediationAI
Upgrade Gitea to v1.27.0 or later; this release scopes the label lookup in DeleteIssueLabel to the URL repository (or its owning organization), mirroring all sibling handlers, so the HTTP status no longer distinguishes cross-tenant label existence. See the advisory at https://github.com/go-gitea/gitea/security/advisories/GHSA-pgqf-926r-548m and the release at https://github.com/go-gitea/gitea/releases/tag/v1.27.0. If immediate patching is not feasible, operators can restrict API access to trusted users only by disabling public registration (reducing the attacker pool to known accounts) or placing the Gitea API behind an authentication proxy; neither eliminates the oracle for existing authenticated users but reduces exposure surface. There is no configuration toggle that disables only the DeleteIssueLabel endpoint without patching.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 3 packages in go, euvd
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
Gitea is a self-hosted Git service written in Go (package: go/code.gitea.io/gitea). The vulnerable handler, DeleteIssueLabel in routers/api/v1/repo/issue_label.go, calls issues_model.GetLabelByID - implemented as a bare e.ID(labelID).Get(l) ORM query with no repo_id or org_id filter in models/issues/label.go. Every sibling handler (GetLabel, EditLabel, DeleteLabel for both repo and org contexts) correctly uses scoped variants GetLabelInRepoByID or GetLabelInOrgByID, returning 404 for foreign label IDs. DeleteIssueLabel is the sole outlier. The downstream service layer (issue_service.RemoveLabel) only validates the doer's write permission on the issue's own repository and never checks that the label belongs to that repository. The root cause is CWE-203 (Observable Discrepancy): differential HTTP responses (204 No Content on global ID hit; 422 ErrLabelNotExist on miss) expose a side-channel. Because label IDs are sequential auto-increments, an attacker can trivially enumerate the entire instance-wide label population with linear scanning.
Know when Gitea gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N
Any authenticated user with standard write:issue on their own repo can exploit the oracle, making PR:L more accurate than vendor's PR:H; no integrity or availability impact applies.
Primary rating from Vendor (https://github.com/go-gitea/gitea).
CVSS VectorVendor: https://github.com/go-gitea/gitea
DescriptionCVE.org
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:
// routers/api/v1/repo/issue_label.go (DeleteIssueLabel)
label, err := issues_model.GetLabelByID(ctx, ctx.PathParamInt64("id")) // global, unscopedGetLabelByID (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 repoalice/secret) creates a label → internal id 1.- Attacker
bob(separate user; public repobob/pubwith issue #1; no access toalice/secret) holds a token
with write:issue on his own repo.
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:
- Create two users
alice,bob. Asalice, create a private repo and a label on it (note the labelidfrom
the API response).
- As
bob, create any repo with an issue, and a token withwrite:issue. curl -u bob:$T -X DELETE https://<gitea>/api/v1/repos/bob/pub/issues/1/labels/<alice_label_id>→ 204.curl -u bob:$T -X DELETE https://<gitea>/api/v1/repos/bob/pub/issues/1/labels/99999999→ 422.- The differing status across an ID
bobcannot 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 loader like every sibling handler, returning 404 for a label that is not in the URL repository (or its owning organization), so the status no longer distinguishes existence:
// routers/api/v1/repo/issue_label.go - in DeleteIssueLabel, after loading the label
if label.RepoID != ctx.Repo.Repository.ID && label.OrgID != ctx.Repo.Repository.OwnerID {
ctx.APIErrorNotFound()
return
}(Equivalently, resolve via GetLabelInRepoByID and, for org repositories, also accept the repo owner's org labels - mirroring the scoping in GetLabel/EditLabel/DeleteLabel.)
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Information disclosure occurs when an application unintentionally exposes sensitive data that aids attackers in reconnaissance or directly compromises security.
Remote code execution in Gitea (self-hosted Git service) via a code-injection flaw (CWE-94) allows attackers to run arbi
Broken access control in Gitea's Composer package registry (versions up to and including 1.26.1) lets remote attackers r
Gitea before 1.16.7 does not escape git fetch remote. Rated high severity (CVSS 7.5), this vulnerability is remotely exp
The git hook feature in Gitea 1.1.0 through 1.12.5 might allow for authenticated remote code execution in customer envir
Improper Neutralization of Input During Web Page Generation (XSS or 'Cross-site Scripting') vulnerability in Gitea Gitea
Authenticated command injection in Dokploy (self-hostable PaaS) versions 0.29.3 through 0.29.12 lets a low-privileged us
Reverse-proxy authentication bypass in the official Gitea Docker image (versions up to and including 1.26.2) allows any
Path traversal in Gitea's Org-mode (`.org`) markup renderer allows an attacker who can get Org-mode content rendered by
Container escape in Gitea act_runner (Docker backend, through act 0.262.0) lets an authenticated user with workflow-exec
models/repo_mirror.go in Gitea before 1.7.6 and 1.8.x before 1.8-RC3 mishandles mirror repo URL settings, leading to rem
Server-side request forgery and internal repository exfiltration in Gitea before 1.27.0 lets a low-privileged authentica
Authorization bypass in Gitea versions 1.22.3 through 1.26.1 allows holders of `public-only` access tokens or OAuth gran
EUVD-2026-58172
GHSA-pgqf-926r-548m
NVD
CVE.org
EPSS
Exploit-DB