Skip to main content

Gitea CVE-2026-58445

LOW
Observable Discrepancy (CWE-203)
2026-07-21 https://github.com/go-gitea/gitea GHSA-pgqf-926r-548m
2.7
CVSS 3.1 · GitHub Advisory

Severity by source

GitHub Advisory PRIMARY
2.7 LOW
AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N
vuln.today AI
4.3 MEDIUM

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.

3.1 AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
4.0 AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N

Primary rating from GitHub Advisory.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
None
Availability
None

Lifecycle Timeline

2
Source Code Evidence Fetched
Jul 21, 2026 - 21:17 vuln.today
Analysis Generated
Jul 21, 2026 - 21:17 vuln.today

DescriptionGitHub Advisory

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).

  1. As bob, create any repo with an issue, and a token with write:issue.
  2. curl -u bob:$T -X DELETE https://<gitea>/api/v1/repos/bob/pub/issues/1/labels/<alice_label_id>204.
  3. curl -u bob:$T -X DELETE https://<gitea>/api/v1/repos/bob/pub/issues/1/labels/99999999422.
  4. 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 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:

go
// 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.)

AnalysisAI

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. …

Unlock full vulnerability intelligence

  • Risk assessment & exploitation conditions
  • Attack chain visualization
  • Remediation with exact patch versions
  • Threat intelligence from 22 sources
  • Personal watchlist & email alerts

Free forever · No credit card required

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata

Access
Authenticate as any Gitea user
Delivery
Obtain write:issue token on attacker-controlled repository
Exploit
Send DELETE /api/v1/repos/{own-repo}/issues/{id}/labels/{target_id}
Execution
Observe 204 (label exists anywhere on instance) vs. 422 (does not exist)
Persist
Iterate sequential label IDs
Impact
Enumerate instance-wide label population across tenant boundaries

Vulnerability AssessmentAI

Exploitation 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. … Additional conditions and limiting factors are described in the full assessment.
Risk Assessment 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). … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in.
Exploit Scenario 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. …
Remediation 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. … Detailed patch versions, workarounds, and compensating controls in full report.

Threat intelligence, references, and detailed analysis are available after sign-in.

More in Gitea

View all
CVE-2026-27771 HIGH POC
8.2 Jul 03

Broken access control in Gitea's Composer package registry (versions up to and including 1.26.1) lets remote attackers r

CVE-2022-30781 HIGH POC
7.5 May 16

Gitea before 1.16.7 does not escape git fetch remote. Rated high severity (CVSS 7.5), this vulnerability is remotely exp

CVE-2020-14144 HIGH POC
7.2 Oct 16

The git hook feature in Gitea 1.1.0 through 1.12.5 might allow for authenticated remote code execution in customer envir

CVE-2024-6886 CRITICAL POC
10.0 Aug 06

Improper Neutralization of Input During Web Page Generation (XSS or 'Cross-site Scripting') vulnerability in Gitea Gitea

CVE-2026-58053 CRITICAL POC
9.4 Jun 28

Container escape in Gitea act_runner (Docker backend, through act 0.262.0) lets an authenticated user with workflow-exec

CVE-2019-11229 HIGH POC
8.8 Apr 15

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

CVE-2020-13246 HIGH POC
7.5 May 20

An issue was discovered in Gitea through 1.11.5. Rated high severity (CVSS 7.5), this vulnerability is remotely exploita

CVE-2022-0905 HIGH POC
7.1 Mar 10

Missing Authorization in GitHub repository go-gitea/gitea prior to 1.16.4. Rated high severity (CVSS 7.1), this vulnerab

CVE-2022-1058 MEDIUM POC
6.1 Mar 24

Open Redirect on login in GitHub repository go-gitea/gitea prior to 1.16.5. Rated medium severity (CVSS 6.1), this vulne

CVE-2026-20896 CRITICAL POC
9.8 Jul 03

Reverse-proxy authentication bypass in the official Gitea Docker image (versions up to and including 1.26.2) allows any

CVE-2026-27780 CRITICAL
9.8 Jul 03

Branch-protection bypass in Gitea's self-hosted Git server (all versions before 1.26.0) allows a user with push access t

CVE-2026-26292 CRITICAL
9.8 Jul 03

Migration transport protections in Gitea are bypassed for Git LFS operations, affecting all self-hosted instances before

Share

CVE-2026-58445 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy