← Back to Feed CACHED · 2026-10-07 09:42:31 · CACHE_KEY CVE-2026-60004
CVE-2026-60004 · CWE-94 · Disclosed 2026-08-26

Gitea Remote Code Execution via diffpatch Git Hook Injection

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

Someone left the keys in the ignition of the factory that builds all your software

CVE-2026-60004 is a code injection flaw in Gitea's diffpatch API endpoint (POST /api/v1/repos/{owner}/{repo}/diffpatch) affecting versions 1.17.0 through 1.27.0. A crafted patch payload triggers an add/add collision in Git's three-way merge logic, causing attacker-controlled content to materialize as an executable Git hook (e.g., post-receive) inside the server-side repository directory. When Git performs any hook-triggering operation, the injected script runs as the Gitea OS service account — typically git or gitea. Because Gitea ships with self-registration enabled by default, an unauthenticated attacker can register an account, create a repository, and achieve full RCE in approximately 11 seconds. Gitea patched this in v1.27.1 on July 27, 2026.

The vendor's CRITICAL / 9.8 rating is fully justified and may even understate operational risk. The CVSS vector marks PR:N (no privileges required), which is accurate for default configurations where open sign-up converts anonymous internet access into authenticated write access in one API call. Real-world exploitation has already graduated from opportunistic crypto-mining to state-aligned APT operations: Acronis documented the Red Heron campaign weaponizing this flaw within 48 hours of PoC publication, compromising 11 organizations across defense, government, and energy sectors in five countries. Shadowserver counted 8,393 vulnerable internet-facing instances as of August 27, 2026. This is not a theoretical risk — it is an active emergency.

"Pre-auth RCE on default Gitea — APT and commodity actors already exploiting at scale"
02 · The Attack Path

5 steps from start to impact.

STEP 01

Reach the Gitea HTTP endpoint

The attacker locates a Gitea instance exposed to the network — either on the internet (8,393+ indexed by Shadowserver) or on an internal network. Gitea's default port is 3000, and its login page fingerprints trivially via the X-Gitea-Version response header. Shodan, FOFA, and Censys dorks return thousands of results. Internal instances are reachable from any host on the same network segment.
Conditions required:
  • Network access to Gitea HTTP port (default 3000)
Where this breaks in practice:
  • Internal-only instances require pre-existing network access — but any developer workstation or CI runner on the same VLAN qualifies
Detection/coverage: Nuclei template CVE-2026-60004.yaml from projectdiscovery detects vulnerable instances. runZero query vendor:=Gitea AND product:=Gitea enumerates assets.
STEP 02

Obtain write access via self-registration

If open registration is enabled (the Gitea default), the attacker registers a new account via /user/sign_up or the API, then creates a new repository. This grants the write access prerequisite. The PoC by imbas007 automates this end-to-end in full-auto mode. If registration is disabled, any compromised developer credential or leaked CI token with repo:write scope suffices.
Conditions required:
  • Open self-registration (Gitea default) OR any valid credential with repo write access
Where this breaks in practice:
  • Instances with DISABLE_REGISTRATION = true require credential theft — but this is not the default
Detection/coverage: Monitor for rapid account creation followed by immediate repository creation. Behavioral indicator: new user → new repo → diffpatch POST within seconds.
STEP 03

Submit malicious diffpatch payload

The attacker sends a crafted POST /api/v1/repos/{owner}/{repo}/diffpatch request containing a patch that induces an add/add collision. Gitea's backend creates a temporary bare clone and applies the patch. Due to the bare-clone behavior, the merge fallback writes attacker-controlled content into a path that resolves as a Git hook (e.g., hooks/post-receive). The file is created with execute permissions. The weaponized PoC (cve-2026-60004-poc.py) handles all encoding and collision crafting automatically.
Conditions required:
  • Write access to at least one repository
  • Vulnerable Gitea version (1.17.0–1.27.0)
Where this breaks in practice:
  • None — the exploit is reliable and deterministic against vulnerable versions
Detection/coverage: WAF rules matching POST to /api/v1/repos/*/diffpatch with anomalous patch content. Log analysis: look for diffpatch API calls from newly registered accounts.
STEP 04

Git hook executes attacker payload

Any subsequent Git operation that triggers the injected hook — including the attacker's own push, or an organic developer commit — causes the hook script to execute as the Gitea service account. The Red Heron campaign used this to download the JITTERLY implant; commodity actors dropped XMRig miners. The Gitea service account typically has read access to all repositories, the Gitea configuration file (containing database credentials, secret keys, OAuth tokens), and the .ssh/authorized_keys file.
Conditions required:
  • A Git operation triggers the hook (attacker can force this immediately)
Where this breaks in practice:
  • None — the attacker controls the trigger
Detection/coverage: Monitor for unexpected child processes of the Gitea/Git process. Watch for modifications to /etc/ld.so.preload, outbound connections from gitea process, new files in /tmp/.X11-unix*.
STEP 05

Post-exploitation: credential harvest and supply-chain pivot

With shell access as the Gitea service account, the attacker reads app.ini to extract database credentials, JWT signing secrets, and OAuth client secrets. They can inject backdoors into any hosted repository's source code — a supply-chain attack affecting every downstream build that pulls from this forge. The Red Heron campaign exfiltrated repositories and pivoted laterally to Proxmox hypervisors in at least one victim environment. The SIXZUT LD_PRELOAD rootkit was deployed for persistence.
Conditions required:
  • Shell access as Gitea service account (achieved in step 4)
Where this breaks in practice:
  • Containerized deployments limit filesystem access — but secrets and repos are still inside the container
Detection/coverage: File integrity monitoring on app.ini and repository hook directories. YARA rules for JITTERLY (SHA256: B441F793...) and SIXZUT (28B132AD...). Network detection: connections to s2.981666.xyz:8082, 72.11.138.109:8888.
03 · Compensating Control

1
CRITICAL 9.8→HIGH 8.8
SEVERITY REDUCED
Disable self-registration immediately — Set DISABLE_REGISTRATION = true in app.ini under [service]. This eliminates the unauthenticated-to-authenticated escalation path, forcing attackers to obtain valid credentials before exploitation. Deploy within the noisgate mitigation SLA of ≤3 days (CRITICAL verdict). Note: this does NOT fix the vulnerability — any authenticated user with write access to any repo can still exploit it.
2
CRITICAL 9.8→LOW 3.1
SEVERITY REDUCED
Restrict or block the diffpatch API endpoint — At your reverse proxy or WAF, block or require additional authentication for POST /api/v1/repos/*/diffpatch. This disables the vulnerable endpoint entirely. Some CI/CD workflows that use the diffpatch API will break — validate before deploying. Apply within ≤3 days.
3
CRITICAL 9.8→MEDIUM 6.5
SEVERITY REDUCED
Network-restrict Gitea to internal access only — Remove Gitea from internet-facing exposure. Place it behind a VPN or zero-trust proxy (e.g., Cloudflare Access, Tailscale, Zscaler). This eliminates the remote unauthenticated attack vector entirely. Internal attackers or compromised internal hosts can still exploit, but the attack surface drops by orders of magnitude. Apply within ≤3 days.
4
CRITICAL 9.8→IGNORE 0.0
SEVERITY REDUCED
Upgrade to Gitea 1.27.2+ — The definitive fix. Version 1.27.1 changes the temporary clone from bare to non-bare, preventing the hook-path collision. Version 1.27.2 includes additional hardening. This is the noisgate remediation SLA target — deploy within ≤90 days, though given active exploitation you should treat this as an emergency patch within hours.
5
CRITICAL 9.8→MEDIUM 5.5
SEVERITY REDUCED
Run Gitea in a hardened container with read-only filesystem — Run the Gitea container with --read-only and explicit writable volume mounts for /data only. This prevents the hook injection from writing to unexpected paths. Also run as a non-root UID to limit post-exploitation pivot. Deploy within ≤3 days if patching is not immediately possible.
What doesn't work
  • Rate-limiting the API — the exploit requires only a single POST request to the diffpatch endpoint; rate-limiting will not prevent exploitation.
  • Gitea's built-in webhook restrictions — these control outbound webhooks, not server-side Git hooks. The vulnerability installs a server-side hook, which bypasses webhook allowlists entirely.
  • Repository permission audits — the attacker creates their own repository; reviewing existing repo permissions does not prevent the attack path.
  • Two-factor authentication on Gitea accounts — MFA protects against credential theft but does not help when the attacker registers their own account via open self-registration.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationConfirmed and active. CISA added to KEV on 2026-08-25. Red Heron APT exploited within 48 hours of PoC release, compromising 11 organizations across defense, government, energy, and aerospace in US, Canada, Taiwan, Argentina, Sri Lanka (Acronis TRU). Commodity crypto-miner campaigns documented on Habr.
Proof-of-ConceptMultiple public PoCs. imbas007/CVE-2026-60004-POC — Python, full-auto mode (registers account → creates repo → exploits → exfils output). 11 total GitHub repos indexed. Nuclei template available (CVE-2026-60004.yaml). ExploitDB entry present.
EPSS0.23988 — top 5% of all scored CVEs. Indicates high predicted exploitation probability, consistent with confirmed in-the-wild activity.
KEV StatusListed 2026-08-25. CISA BOD 22-01 federal remediation deadline: 2026-08-28 (3-day window). This is among the shortest remediation windows CISA has ever mandated.
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H — Network-attackable, low complexity, no privileges required, no user interaction, full CIA impact. The PR:N is accurate because default open registration converts anonymous access to write access.
Affected VersionsGitea 1.17.0 through 1.27.0 inclusive. Fixed in 1.27.1 (2026-07-27). A further hardened release 1.27.2 followed.
Exposure DataShadowserver identified 8,393 vulnerable internet-facing instances as of 2026-08-27 (BleepingComputer). Red Heron scanned 1,386 instances across 7 countries and maintained a separate Taiwan-focused list of 477 targets.
Reporting ResearcherShai Rod (aka NightRang3r), Salesforce security team. Responsible disclosure to Gitea project; patch shipped 2026-07-27, advisory published 2026-07-28.
Threat Actor ActivityRed Heron (suspected state-aligned): deployed JITTERLY C++ implant (30+ post-exploitation commands) and SIXZUT LD_PRELOAD rootkit. C2: s2.981666.xyz:8082. Pivoted from Gitea to Proxmox hypervisors. Targeted defense, elections, energy sectors.
Detection CoverageNuclei template available. No specific Sigma rule published yet but behavioral indicators are well-documented: rapid registration→repo→diffpatch sequence, child processes spawned by Gitea service, modifications to hook directories.

Sources.

  1. CISA KEV Alert — CVE-2026-60004 Added
  2. BleepingComputer — Over 8,300 Gitea Servers Vulnerable
  3. Acronis TRU — Red Heron Campaign and SIXZUT Rootkit
  4. Help Net Security — CVE-2026-60004 Exploited in the Wild
  5. imbas007/CVE-2026-60004-POC — Full-Auto Python Exploit
  6. SOC Prime — Detection Guidance and Miner Payload Analysis
  7. runZero — Finding Vulnerable Gitea Assets
  8. SecurityWeek — CISA Warns of Exploited Gitea Vulnerability
05 · The Call

Final Verdict
= UNCHANGED to CRITICAL (9.8/10)

Why this verdict

  • Default config = pre-auth RCE: Gitea ships with ENABLE_OPENID_SIGNUP and ALLOW_ONLY_EXTERNAL_REGISTRATION off, meaning self-registration is enabled by default. This converts PR:N in the CVSS vector from theoretical to literal — any anonymous internet user can register, create a repo, and achieve RCE in ~11 seconds.
  • Active APT and commodity exploitation: Red Heron weaponized this within 48 hours of PoC publication, compromising defense and government targets across five countries. Commodity actors are independently deploying crypto miners. This is not a future risk — it is happening now.
  • Weaponization is turnkey: The imbas007 PoC is a single Python script with a --mode full-auto flag that handles registration, repo creation, exploit delivery, and output exfiltration. No manual steps, no binary dependencies, no exploit development skill required.
  • Role multiplier: Gitea is canonically a CI/CD and source-code forge component — it occupies the supply-chain-scale high-value role by definition. Compromise of a Gitea instance gives the attacker write access to every hosted repository (supply-chain pivot), database credentials, OAuth tokens, SSH keys, and JWT signing secrets. In the Red Heron campaign, attackers pivoted from Gitea to Proxmox hypervisors — demonstrating domain/fleet-scale blast radius. Because Gitea IS the forge, ≥90% of Gitea installations occupy this high-value role, placing the verdict floor at CRITICAL.
  • 8,393 exposed instances, 11-second exploit chain: Shadowserver data shows thousands of internet-facing targets. The attack is fully automated and completes faster than most detection pipelines can alert. No friction point in the chain meaningfully reduces the population of exploitable targets on default configurations.

Why not higher?

The CVSS scale caps at 10.0 and this scores 9.8. The only missing tenth is Scope:Changed — the exploit runs as the Gitea service account, not as root (though privilege escalation from git to root is trivial on many Linux deployments, especially containerized ones where the service runs as UID 0). There is no basis to exceed the vendor score.

Why not lower?

Every friction-based downgrade argument fails here. *'Requires authentication'* — no, default config allows self-registration. *'Requires internal network'* — no, 8,393+ instances are internet-facing and attackers are actively scanning for them. *'Requires specific configuration'* — no, the default configuration is exploitable. *'Limited blast radius'* — no, Gitea is a code forge; compromise yields supply-chain access to all hosted repositories. The deployment-role floor for a CI/CD/forge component with confirmed fleet-scale outcomes is CRITICAL, and no friction point in this chain breaks below that floor.

06 · Verification

Crowdsourced verification payload.

Run this script on the Gitea host or from any machine with network access to the Gitea instance. Invoke as: bash check_cve_2026_60004.sh https://gitea.example.com:3000 — no special privileges required; it queries the unauthenticated /api/v1/version endpoint.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_60004.sh — Detect CVE-2026-60004 (Gitea diffpatch RCE)
# Usage: bash check_cve_2026_60004.sh <GITEA_BASE_URL>
# Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN

set -euo pipefail

if [ $# -lt 1 ]; then
  echo "Usage: $0 <GITEA_BASE_URL>"
  echo "Example: $0 https://gitea.example.com:3000"
  exit 2
fi

BASE_URL="${1%/}"
API_URL="${BASE_URL}/api/v1/version"

# Fetch version from Gitea API
RESPONSE=$(curl -sf --max-time 10 "${API_URL}" 2>/dev/null) || {
  echo "UNKNOWN — could not reach ${API_URL}"
  exit 2
}

VERSION=$(echo "${RESPONSE}" | grep -oP '"version"\s*:\s*"\K[^"]+' 2>/dev/null) || {
  echo "UNKNOWN — could not parse version from response"
  exit 2
}

echo "Detected Gitea version: ${VERSION}"

# Parse major.minor.patch
IFS='.' read -r MAJOR MINOR PATCH <<< "$(echo "${VERSION}" | grep -oP '^[0-9]+\.[0-9]+\.[0-9]+')"

if [ -z "${MAJOR:-}" ] || [ -z "${MINOR:-}" ] || [ -z "${PATCH:-}" ]; then
  echo "UNKNOWN — could not parse semantic version from '${VERSION}'"
  exit 2
fi

# Vulnerable: 1.17.0 <= version <= 1.27.0
# Fixed: >= 1.27.1
if [ "${MAJOR}" -eq 1 ]; then
  if [ "${MINOR}" -ge 17 ] && [ "${MINOR}" -le 26 ]; then
    echo "VULNERABLE — Gitea ${VERSION} is in the affected range (1.17.0–1.27.0). CVE-2026-60004 applies."
    exit 1
  elif [ "${MINOR}" -eq 27 ] && [ "${PATCH}" -eq 0 ]; then
    echo "VULNERABLE — Gitea ${VERSION} is in the affected range (1.17.0–1.27.0). CVE-2026-60004 applies."
    exit 1
  elif [ "${MINOR}" -eq 27 ] && [ "${PATCH}" -ge 1 ]; then
    echo "PATCHED — Gitea ${VERSION} contains the fix for CVE-2026-60004."
    exit 0
  elif [ "${MINOR}" -ge 28 ]; then
    echo "PATCHED — Gitea ${VERSION} is beyond the affected range."
    exit 0
  elif [ "${MINOR}" -lt 17 ]; then
    echo "PATCHED — Gitea ${VERSION} predates the affected range (1.17.0+). Not vulnerable to CVE-2026-60004."
    exit 0
  fi
elif [ "${MAJOR}" -gt 1 ]; then
  echo "PATCHED — Gitea ${VERSION} is beyond the affected major version."
  exit 0
fi

echo "UNKNOWN — could not determine vulnerability status for version ${VERSION}"
exit 2