CISA added CVE-2026-60004 to the Known Exploited Vulnerabilities catalog on 2026-08-25, which means this is not a theoretical hardening item: defenders should assume active exploitation pressure against reachable or internally exposed Gitea instances. The affected component is Gitea's diffpatch API endpoint. An attacker who already has repository write access can submit a malicious patch that plants an executable Git hook and causes shell commands to run as the Gitea service account.
This is a classic developer-platform blast-radius problem. Compromising the Gitea service account can expose source code, CI secrets, deploy keys, webhook tokens, package-registry credentials, and any downstream system that trusts repositories or automation running from Gitea. If Gitea is internet-facing, treat this as an incident-response candidate, not just a patch ticket.
Technical analysis
Affected product/platform: Gitea self-hosted instances, commonly deployed on Linux behind a reverse proxy, in Docker/Kubernetes, or as a standalone service. The cited KEV summary does not publish affected version ranges or a CVSS score; do not wait for perfect scoring data. The KEV listing and the described primitive are sufficient to prioritize emergency remediation.
Attack chain from a defender's perspective:
- Attacker obtains or already controls an account/token with write access to a repository. This may be a stolen developer credential, abused CI token, malicious insider, compromised OAuth app, or a previously low-value account on an instance with permissive registration.
- Attacker sends a crafted patch to the Gitea diffpatch API endpoint.
- The patch handling path writes or updates an executable Git hook inside repository data, for example under the Gitea repositories directory in a hooks subdirectory.
- A later Git operation triggers the hook.
- Commands execute with the privileges of the Gitea service account, often named
git,gitea, or a container runtime user.
Why it is dangerous: Git hooks are executable code by design. On a forge server, that design becomes an RCE path when patch/diff logic can be coerced into placing attacker-controlled content where Git will execute it. The service account frequently owns the entire repository tree, database connection secrets, configured credentials, and sometimes SSH host keys or signing material. Even when Gitea runs in a container, mounted volumes, environment variables, outbound network access, and CI integration can make container compromise equivalent to pipeline compromise.
Exploitation status: Confirmed in the CISA KEV as of 2026-08-25. Treat as actively exploited. Validate your vendor advisory and the KEV entry for exact fixed versions, mitigations, BOD 26-04 due dates, and forensic-triage requirements before closure.
Detection and response
Priority telemetry sources are Linux process execution, Gitea/reverse-proxy access logs, file creation under the Gitea repositories path, systemd journal logs for the Gitea unit, container runtime audit logs, and authentication logs for repository write/API events.
---
title: Gitea Service Account Spawning Shell or Interpreter
id: 9f2c7a10-6000-4a04-8c11-cve202660004
description: Detects shells, interpreters, or download tools launched by the Gitea process tree, consistent with malicious Git hook execution after diffpatch abuse.
references:
- https://www.cisa.gov/known-exploited-vulnerabilities-catalog?search_api_fulltext=CVE-2026-60004
- https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/08/25
status: experimental
tags:
- attack.execution
- attack.t1059
logsource:
product: linux
category: process_creation
detection:
selection_parent:
ParentImage|endswith:
- '/gitea'
- '/git'
ParentCommandLine|contains:
- 'gitea web'
- 'gitea serv'
selection_child:
Image|endswith:
- '/sh'
- '/bash'
- '/dash'
- '/zsh'
- '/python'
- '/python3'
- '/perl'
- '/curl'
- '/wget'
- '/nc'
- '/busybox'
condition: selection_parent and selection_child
falsepositives:
- Legitimate administrator maintenance over the service account
- Gitea upgrade or backup scripts run interactively
level: high
---
title: Executable Git Hook Created Under Gitea Repository Storage
id: 3e5ab600-0426-4c25-9004-60004202626
description: Detects creation or modification of executable files in Git hooks directories beneath Gitea repository storage, a high-signal artifact for planted hook persistence.
references:
- https://www.cisa.gov/known-exploited-vulnerabilities-catalog?search_api_fulltext=CVE-2026-60004
- https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/08/25
status: experimental
tags:
- attack.persistence
- attack.execution
- attack.t1059
logsource:
product: linux
category: file_event
detection:
selection_path:
TargetFilename|contains:
- '/repositories/'
- '/hooks/'
selection_names:
TargetFilename|endswith:
- '/pre-receive'
- '/post-receive'
- '/update'
- '/pre-push'
- '/post-commit'
- '/pre-commit'
- '/applypatch-msg'
- '/commit-msg'
- '/prepare-commit-msg'
condition: selection_path and selection_names
falsepositives:
- Rare legitimate server-side hook management by platform administrators
- Migration tooling that intentionally installs hooks
level: high
---
title: Suspicious POSTs to Gitea diffpatch API From Low-Trust Sources
id: 7b260004-2026-408a-94c5-2604260004
description: Detects HTTP POST requests to Gitea diffpatch API paths, useful when paired with identity, source reputation, and subsequent hook file creation.
references:
- https://www.cisa.gov/known-exploited-vulnerabilities-catalog?search_api_fulltext=CVE-2026-60004
- https://attack.mitre.org/techniques/T1190/
author: Security Arsenal
date: 2026/08/25
status: experimental
tags:
- attack.initial_access
- attack.t1190
logsource:
category: webserver
detection:
selection_method:
cs-method: 'POST'
selection_uri:
cs-uri|contains:
- 'diffpatch'
- '/api/v1/repos/'
condition: selection_method and selection_uri
falsepositives:
- Legitimate developer API use
- Repository automation and migration tools
level: medium
let lookback = 14d;
let shells = dynamic(['sh','bash','dash','zsh','python','python3','perl','curl','wget','nc','busybox']);
let Proc = DeviceProcessEvents
| where Timestamp >= ago(lookback)
| where InitiatingProcessFileName has_any ('gitea','git') or InitiatingProcessCommandLine has_any ('gitea web','gitea serv')
| where FileName has_any (shells) or ProcessCommandLine has_any ('/hooks/','diffpatch','curl http','wget http','base64 -d')
| project Timestamp, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, AccountName, SHA256, ReportId;
let Web = CommonSecurityLog
| where TimeGenerated >= ago(lookback)
| where RequestMethod == 'POST' and (RequestURL has 'diffpatch' or RequestURL has '/api/v1/repos/')
| project TimeGenerated, SourceIP, SourceUserName, RequestURL, RequestMethod, DeviceVendor, DeviceProduct, LogSeverity;
let Sys = Syslog
| where TimeGenerated >= ago(lookback)
| where SyslogMessage has_any ('diffpatch','/hooks/','gitea','pre-receive','post-receive')
| project TimeGenerated, Computer, Facility, SeverityLevel, SyslogMessage;
Proc
| union (Web | project-rename Timestamp=TimeGenerated), (Sys | project-rename Timestamp=TimeGenerated)
| sort by Timestamp desc
-- Triages Gitea-linked process execution and server-side Git hook artifacts on Linux endpoints.
LET proc = SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE Exe =~ '/gitea|/git'
OR CommandLine =~ 'gitea web|gitea serv|/hooks/|diffpatch'
OR Name =~ '^(sh|bash|dash|zsh|python3?|perl|curl|wget|nc|busybox)$';
LET hooks = SELECT FullPath, Size, Mtime, Ctime, Mode.String AS Mode
FROM glob(globs=['/var/lib/gitea/repositories/**/hooks/*','/data/git/repositories/**/hooks/*','/home/git/gitea-repositories/**/hooks/*'])
WHERE Mode =~ 'x' OR FullPath =~ 'pre-receive$|post-receive$|update$|pre-push$|post-commit$';
SELECT 'process' AS ArtifactType, Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime, NULL AS FullPath, NULL AS Mtime, NULL AS Mode FROM proc
UNION ALL
SELECT 'hook_file' AS ArtifactType, NULL AS Pid, NULL AS Ppid, NULL AS Name, NULL AS Exe, NULL AS CommandLine, NULL AS Username, NULL AS CreateTime, FullPath, Mtime, Mode FROM hooks
#!/usr/bin/env bash
# Emergency triage for CVE-2026-60004. Run as root or with sudo. Review before stopping services.
set -euo pipefail
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
OUT="/var/tmp/gitea-cve-2026-60004-$STAMP"
mkdir -p "$OUT"
printf '%s\n' '[*] Collecting service, package, and process context'
(systemctl status gitea --no-pager || true) > "$OUT/gitea-service.txt" 2>&1
(command -v gitea && gitea --version || true) > "$OUT/gitea-version.txt" 2>&1
(dpkg -l | grep -i gitea || rpm -qa | grep -i gitea || true) >> "$OUT/gitea-version.txt" 2>&1
ps -eo user,pid,ppid,comm,args | grep -Ei 'gitea|git' | grep -v grep > "$OUT/gitea-processes.txt" || true
ss -lntup | grep -Ei ':3000|:22|gitea' > "$OUT/listeners.txt" || true
printf '%s\n' '[*] Finding executable Git hooks in common Gitea repository paths'
for p in /var/lib/gitea/repositories /data/git/repositories /home/git/gitea-repositories /opt/gitea/repositories; do
[ -d "$p" ] && find "$p" -type f -path '*/hooks/*' -perm /111 -printf '%TY-%Tm-%TdT%TH:%TM:%TSZ %u %g %m %p\n' >> "$OUT/executable-hooks.txt" || true
done
[ -f "$OUT/executable-hooks.txt" ] || touch "$OUT/executable-hooks.txt"
printf '%s\n' '[*] Quarantining unexpected executable hooks without deleting evidence'
while IFS= read -r line; do
f=${line##* }
case "$f" in
*/hooks/*)
cp -a --parents "$f" "$OUT/evidence/" 2>/dev/null || true
chmod 0644 "$f" 2>/dev/null || true
mv "$f" "$f.disabled.$STAMP" 2>/dev/null || true
printf '%s\n' "$f" >> "$OUT/quarantined.txt"
;;
esac
done < <(awk '{print $NF}' "$OUT/executable-hooks.txt")
printf '%s\n' '[*] Pulling recent Gitea, proxy, and auth indicators'
(journalctl -u gitea --since '14 days ago' --no-pager || true) > "$OUT/gitea-journal.txt" 2>&1
for lg in /var/log/nginx/access.log /var/log/apache2/access.log /var/log/gitea/*.log; do
[ -f "$lg" ] && grep -Ei 'POST .*diffpatch|/api/v1/repos/|Failed password|session opened' "$lg" >> "$OUT/access-indicators.txt" || true
done
[ -f "$OUT/access-indicators.txt" ] || touch "$OUT/access-indicators.txt"
last -a | head -100 > "$OUT/last-logins.txt" || true
getent passwd git gitea > "$OUT/service-users.txt" 2>&1 || true
sudo -l -U git > "$OUT/git-sudo.txt" 2>&1 || true
sudo -l -U gitea > "$OUT/gitea-sudo.txt" 2>&1 || true
printf '%s\n' '[*] Applying temporary service-account guardrails where safe'
for u in git gitea; do
if id "$u" >/dev/null 2>&1; then
usermod -s /usr/sbin/nologin "$u" 2>/dev/null || usermod -s /sbin/nologin "$u" 2>/dev/null || true
fi
done
if systemctl cat gitea >/dev/null 2>&1; then
mkdir -p /etc/systemd/system/gitea.service.d
cat > /etc/systemd/system/gitea.service.d/90-cve-2026-60004.conf <<'EOF'
[Service]
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/gitea /etc/gitea /var/log/gitea
CapabilityBoundingSet=
LockPersonality=true
RestrictSUIDSGID=true
EOF
systemctl daemon-reload
fi
printf '%s\n' "[*] Triage bundle written to $OUT"
printf '%s\n' '[*] Next: patch per Gitea advisory, block or tightly restrict diffpatch at the proxy until patched, rotate repo/CI/webhook secrets, and review quarantined hooks.'
Remediation
- Confirm exposure immediately. Inventory all self-hosted Gitea instances, including containers, test instances, mirrors, and appliances bundled with CI. Check whether the service is internet-reachable or reachable from broad internal networks.
- Apply the vendor fix or documented mitigation for CVE-2026-60004. Use the Gitea release advisory referenced by the CISA KEV entry as the source of truth for exact fixed versions. The provided KEV summary does not include version numbers, so do not rely on secondary blogs for patch targets.
- If you cannot patch, isolate. Place Gitea behind VPN/ZTNA, disable open registration, remove anonymous access, and restrict repository write/API access to trusted groups. At the reverse proxy, consider temporarily blocking or allowlisting
POSTrequests to diffpatch/API repository paths only after testing against developer workflows. Do not leave a vulnerable instance broadly reachable while waiting for a change window. - Reduce privilege. Run Gitea as a dedicated non-root account with no sudo, no interactive shell, minimal filesystem write scope, systemd sandboxing where supported, and no cloud metadata or wildcard network egress unless required. In containers, drop capabilities, set
no-new-privileges, use read-only root filesystems where possible, and avoid mounting Docker sockets. - Hunt before declaring clean. Search at least 14 days back for diffpatch POSTs, executable hooks under repository storage, child processes of the Gitea service, unexpected outbound connections from the Gitea host, new SSH keys, new tokens/apps, changed webhooks, force pushes, and repository permission changes.
- Rotate trust material if any suspicious hook or process is found. Revoke user and CI tokens, deploy keys, OAuth apps, webhook secrets, signing keys reachable by the service account, package registry credentials, and any secrets present in repositories or CI variables. Assume source code and pipeline secrets were exposed.
- Meet governance obligations. Follow CISA BOD 26-04 risk-prioritization guidance, the KEV due date for your organization where applicable, and CISA forensic-triage requirements. Preserve access logs, repository metadata, hook files, systemd journals, container logs, and authentication records before destructive cleanup. If mitigations are unavailable for cloud-managed use, follow BOD 26-04 cloud guidance or discontinue use until a supported control exists.
- Validate after remediation. Re-run the hook-file search, confirm no Gitea-spawned shell processes remain, review proxy logs for continued diffpatch probing, and alert on any new executable hook creation outside a documented admin change.
Related Resources
Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.