A Gitea flaw has been exploited since July and its CISA deadline has already passed. The 9.8 depends on a setting you can change tonight
CVE-2026-60004 lets a patch submitted twice plant a live Git hook and run code as the Gitea service account. Public exploit code appeared a day after the fix and four weeks before the CVE. Shadowserver counts 8,393 vulnerable IPs. The vector says no privileges needed; the vendor advisory says repository write access, and open registration is what closes that gap.
By Parminder Kumar Sharma · · 9 min read

What is happening
CVE-2026-60004 is a remote code execution flaw in Gitea, the self-hosted Git service. It is scored 9.8, it has been exploited in the wild, and CISA added it to the Known Exploited Vulnerabilities catalogue on 25 August 2026 with a remediation deadline of 28 August. That deadline has passed.
On 27 August, the Shadowserver Foundation reported 8,393 IP addresses still presenting a vulnerable version. Exploit code has been public since 29 July, one day after the fix.
The most useful thing in this story is not the score. It is that the score describes a default, and you may be able to change your exposure tonight without deploying anything.
The 9.8 is partly a configuration setting
There is a real discrepancy between the CVE vector and the vendor advisory, and it is not a mistake. It is the whole practical picture.
One flaw, two threat models, decided by a config line
PR:N, scoring 9.8, and public exploits describe it as pre-auth. Gitea’s own advisory is narrower: “An attacker with write access to a repository”, adding that “with open registration enabled, unauthenticated visitors can obtain write access by creating an account and repository.” Both descriptions are correct; which one applies to you is a setting.The CVE record scores it CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, and PR:N means no privileges required. Gitea’s own advisory is narrower: "An attacker with write access to a repository can execute arbitrary shell commands as the Gitea OS user." It then explains the gap itself: "With open registration enabled, unauthenticated visitors can obtain write access by creating an account and repository."
So on a default internet-facing Gitea, a stranger registers, creates a repository, and posts to the diffpatch endpoint. That is pre-authentication in every sense that matters. On an instance with registration closed, the same code needs an account that already has write access, which is a serious insider problem but not a stranger-with-a-scanner problem. The severity is a property of your deployment, not only of the bug.
The mechanism, in one line of the fix
The bug is a neat one. Gitea applies a submitted patch inside a bare temporary clone. Submit the same patch twice, and the add/add collision pushes Git into its three-way merge fallback, which writes the indexed path to disk despite the --cached flag. In a bare repository the root is the Git directory, so a file materialised at hooks/post-index-change becomes a live Git hook, and Git then runs it while writing the index.
The fix is one boolean:
// services/repository/files/patch.go
- if err := t.Clone(ctx, opts.OldBranch, true); err != nil {
+ // here must NOT use bare repo, because the following git commands
+ // might operate working tree ("--index") directly
+ if err := t.Clone(ctx, opts.OldBranch, false); err != nil {
Stop using a bare clone, and a written file is no longer a hook.
Patch to 1.27.2, not 1.27.1
This is the correction most worth carrying away, because the natural instinct is wrong.
Which version actually gets you clear
| Version | Released | What it does |
|---|---|---|
| 1.17 to 1.27.0 | - | Affected by CVE-2026-60004 |
| 1.27.1 | 27 July 2026 | Fixes CVE-2026-60004, and CVE-2026-59774, an unauthenticated arbitrary file read |
| 1.27.2 | 14 August 2026 | Fixes seven more issues including CVE-2026-73539, a second RCE via argument injection in the markup renderer |
An administrator reading the KEV entry and stopping at 1.27.1 closes the exploited hole and leaves a different remote code execution path open. Go to 1.27.2 or later.
What is actually known about the attacks
Here the reporting deserves a careful read, because a specific claim is travelling further than its evidence.
CISA is unambiguous that exploitation is real: its own machine-readable enrichment records exploitation: active, automatable: yes, technicalImpact: total. But KEV records knownRansomwareCampaignUse: Unknown, no threat actor has been named, and no vendor or incident-response telemetry on exploitation volume has been published. Real exploitation, thinly characterised.
Read the 8,393 correctly
8,393
IPs flagged vulnerable
Unique IP addresses, not organisations, from a version-based scan on 27 August.
25 Aug
added to CISA KEV
With a remediation due date of 28 August under BOD 26-04, a three-day window.
29 Jul
first public exploit
One day after the advisory, and about four weeks before the CVE was published.
1.27.2
the version to reach
1.27.1 fixes this flaw; 1.27.2 closes a second, separate RCE.
Two caveats on that headline number, both from Shadowserver’s own methodology. It counts unique IP addresses, not installations or organisations. And it is a version-based scan: it identifies hosts advertising a version in the affected range. It cannot see whether registration is disabled, whether the diffpatch route is reachable, or whether a proxy sits in front, all of which change exploitability. Shadowserver says plainly of this class of check that "this is a version based scan" and that false positives are possible. Treat 8,393 as a population of instances worth checking, not a count of compromisable servers.
There is also an unexplained inconsistency worth noting rather than smoothing over: two days earlier, coverage cited a different Shadowserver dataset for roughly 5,000 exposed instances. A "vulnerable" count exceeding an "exposed" count is not reconcilable from public data, because the two figures come from different collection methods. They are not a trend.
The timeline is the lesson
Four weeks of exposure before most defenders had a CVE
26 to 27 Jul
Fixed and released
The fix merges and Gitea 1.27.1 ships, with the security advisory published on 28 July.
29 Jul
Public exploit appears
The first public exploit repository is created, one day after the advisory. Eight more follow.
14 Aug
1.27.2 ships
A second, separate remote code execution flaw is fixed. Anyone who stopped at 1.27.1 is still exposed to it.
19 Aug
First public incident write-up
A self-reported homelab compromise documents the full chain in about eleven seconds.
25 to 28 Aug
KEV, with a three-day clock
CISA adds the flaw on 25 August with a 28 August due date, and Shadowserver reports 8,393 vulnerable IPs on the 27th.
The CVE was only published on 26 August, four weeks after working exploit code was public. A team tracking risk by CVE feed had no identifier to track during the entire window when the exploit existed and the patch did not appear urgent. The fix was available the whole time, in a routine release.
What to do
Take this with you
For anyone running self-hosted Gitea
- Upgrade to 1.27.2 or later, not 1.27.1. The KEV entry names this flaw, but stopping at the version that fixes it leaves a second remote code execution flaw, CVE-2026-73539, open.
- Close self-registration tonight if you cannot patch tonight. Set DISABLE_REGISTRATION, or at minimum require email confirmation or admin approval, and disable OpenID signup. That is the control that turns a stranger-reachable flaw into an insider one.
- Assume compromise if you were internet-facing and unpatched, and act like it. CISA requires forensic triage, not just patching. Hunt for files at hooks/post-index-change, short random-named executables in temporary directories, and sustained CPU anomalies.
- Rotate everything the service account could read. The advisory lists application config and secrets, the process environment, mounted repositories, database credentials and contents, and OAuth and integration tokens. A code-hosting compromise is a credential compromise.
- Restrict egress from the Gitea host. In the one documented incident every stage after the initial hook needed outbound access to fetch a loader and then a payload. An instance that cannot reach the internet outbound breaks that chain.
The position
Everything needed to avoid this was public and unremarkable. The fix shipped in a routine release on 27 July. The advisory explained the flaw plainly, including the registration nuance, on 28 July. What arrived late was the CVE identifier, four weeks after the exploit, which is the artefact most vulnerability programmes are actually wired to. This site keeps finding the same defect: a feed that is accurate and answers a narrower question than the buyer assumes, consumed as though it were early warning.
The second lesson is more encouraging. A 9.8 that reads as unconditional turns out, on reading the vendor’s own words, to depend on a setting many organisations can change in a minute. That is not a reason to delay patching, and 8,393 hosts are visibly still advertising the vulnerable version. But when a number and an advisory disagree, the advisory usually contains the operational detail, and here it contains a control you can apply before your change window opens.
Sources
- PrimaryRemote Code Execution via diffpatch Git Hook Installation (GHSA-rcr6-4jqh-j84m), 28 July 2026Giteaaccessed 2026-08-29
- PrimaryKnown Exploited Vulnerabilities Catalog, CVE-2026-60004 added 25 August 2026CISAaccessed 2026-08-29
- PrimaryRelease of 1.27.2, 14 August 2026Giteaaccessed 2026-08-29
- Primary8,393 IPs found vulnerable to CVE-2026-60004 on 2026-08-27Shadowserver Foundationaccessed 2026-08-29


