Skip to main content

Gitea 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 · GitHub Advisory
Share

Severity by source

GitHub Advisory 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

Primary rating from GitHub Advisory.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N
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

DescriptionGitHub Advisory

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. …

Unlock full vulnerability intelligence

  • Risk assessment & exploitation conditions
  • Attack chain visualization
  • Remediation with exact patch versions
  • Threat intelligence from 22 sources
  • Personal watchlist & email alerts

Free forever · No credit card required

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata

Recon
Craft pull_request.yml with attacker-controlled cloneURL
Delivery
Package as valid restore-repo dump archive
Exploit
Deliver dump to Gitea administrator
Install
Admin runs gitea restore-repo on server host
C2
CheckAndEnsureSafePR called with empty baseURL, bypassing all URL validation
Execute
Gitea executes git remote add and git fetch against attacker URL
Impact
SSRF reaches internal services or file:// discloses local git repos

Vulnerability AssessmentAI

Exploitation The `gitea restore-repo` CLI command must be executed by a Gitea administrator on the server host, processing a dump directory that the attacker controls or has tampered with. … Additional conditions and limiting factors are described in the full assessment.
Risk Assessment The provided CVSS 3.1 score of 6.3 (Medium) with vector AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N is internally consistent: the attack vector is local (CLI invocation on the Gitea server host), complexity is low once triggered, no attacker privileges are required, but an administrator must actively run the restore command (UI:R). … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in.
Exploit Scenario An attacker crafts a minimal Gitea dump directory containing a `pull_request.yml` with `head.cloneURL` set to `http://169.254.169.254/latest/meta-data/iam/security-credentials/` (the AWS IMDSv1 endpoint). The dump is delivered to a Gitea administrator under the guise of a legitimate repository migration from a partner organization. …
Remediation Upgrade Gitea to v1.27.0 or later, which resolves the missing URL validation in the `restore-repo` path. … Detailed patch versions, workarounds, and compensating controls in full report.

Threat intelligence, references, and detailed analysis are available after sign-in.

More in Gitea

View all
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-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-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

CVE-2022-1058 MEDIUM POC
6.1 Mar 24

Open Redirect on login in GitHub repository go-gitea/gitea prior to 1.16.5. Rated medium severity (CVSS 6.1), this vulne

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-27780 CRITICAL
9.8 Jul 03

Branch-protection bypass in Gitea's self-hosted Git server (all versions before 1.26.0) allows a user with push access t

CVE-2026-26292 CRITICAL
9.8 Jul 03

Migration transport protections in Gitea are bypassed for Git LFS operations, affecting all self-hosted instances before

Share

CVE-2026-58441 vulnerability details – vuln.today

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