P.K. SHARMA

Cyber security intelligence, AI governance, practitioner analysis

AI Security

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

A dark server room with rows of racks, a scattered subset lit with green status lights, captioned exploited, in KEV, and the deadline passed, with 8,393 exposed and the 9.8 described as a config setting

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

ONE FLAW, TWO THREAT MODELS, DECIDED BY A CONFIG LINEThe advisory says it needs repository write access. The default lets a stranger grant it to themselves.CVE-2026-60004one code flawis registrationopen?yes, the defaultEffectively pre-authenticationregister → create a repo → POST /diffpatch → RCEa stranger manufactures the privilege the flaw requiresnoAn insider or stolen-credential problemneeds an existing account that already has write accessstill serious, but not reachable by a strangerPatch either way. But if you cannot patch tonight, closing registration is the control that changes the threat model.
The CVE vector is 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 vector says no privileges required. The vendor advisory says repository write access. Both are true, and which applies to you depends on whether self-registration is enabled.

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

VersionReleasedWhat it does
1.17 to 1.27.0-Affected by CVE-2026-60004
1.27.127 July 2026Fixes CVE-2026-60004, and CVE-2026-59774, an unauthenticated arbitrary file read
1.27.214 August 2026Fixes seven more issues including CVE-2026-73539, a second RCE via argument injection in the markup renderer
Versions and dates from Gitea's release notes and the GHSA advisory. 1.27.1 fixes this flaw; 1.27.2 fixes a second, separate remote code execution flaw published two weeks later.

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.

Shadowserver Foundation, reported 28 August 2026 for a 27 August scan; KEV dates from the CISA catalogue; exploit-code date from the earliest public repository.

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

  1. 26 to 27 Jul

    Fixed and released

    The fix merges and Gitea 1.27.1 ships, with the security advisory published on 28 July.

  2. 29 Jul

    Public exploit appears

    The first public exploit repository is created, one day after the advisory. Eight more follow.

  3. 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.

  4. 19 Aug

    First public incident write-up

    A self-reported homelab compromise documents the full chain in about eleven seconds.

  5. 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.

Dates from the Gitea advisory and release notes, the earliest public exploit repository, the CVE record and the CISA KEV catalogue.

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

  1. PrimaryRemote Code Execution via diffpatch Git Hook Installation (GHSA-rcr6-4jqh-j84m), 28 July 2026Giteaaccessed 2026-08-29
  2. PrimaryKnown Exploited Vulnerabilities Catalog, CVE-2026-60004 added 25 August 2026CISAaccessed 2026-08-29
  3. PrimaryRelease of 1.27.2, 14 August 2026Giteaaccessed 2026-08-29
  4. Primary8,393 IPs found vulnerable to CVE-2026-60004 on 2026-08-27Shadowserver Foundationaccessed 2026-08-29

Share this briefing

Know someone who owns this problem? Send it to them.

Related briefings

The briefing, in your inbox

Practitioner analysis of cyber and AI security news. No vendor noise.

One email per briefing. Unsubscribe any time.