/* cve2026_60004_artifacts.yar — Xpectra Security Research (2026-08-27) Artefact-layer detection for CVE-2026-60004 (Gitea RCE via diffpatch Git-hook installation, GHSA-rcr6-4jqh-j84m, >=1.17 <1.27.1, CVSS 9.8, CISA KEV dateAdded 2026-08-25). DISCOVERY CREDIT: the vendor published the working exploit inside the advisory. Nothing here claims discovery. WHY THIS LAYER EXISTS AND WHAT IT CANNOT DO ------------------------------------------- The fix (d7bc52be) changed no `git apply` flag and added no path blacklist, it only stopped cloning the temp repo as bare. A byte-identical patch is inert on 1.27.1. So a content signature over the patch describes the ATTACK ATTEMPT, not the compromise: it will hit staged copies of the advisory PoC on patched hosts, on blue-team exercise boxes, and in your own lab. Rules 1 and 2 are labelled as such. Rule 3 is behaviour-shaped (WHERE the hook is) and is the one that separates executed from blocked. Negative controls, all live-fired (detection/run_yara.sh): * the real stock hook directory of a real repository on the target container (git's *.sample templates + Gitea's post-receive/pre-receive/proc-receive/ update, 21 files) - they carry "#!/bin/sh" and the word "hooks" and must NOT match; * the benign HTTP requests from our own pcap (POST /contents/benign.txt, POST /api/v1/user/repos); * rule 3 additionally fired against our attack hook with a legitimate-looking path, to prove the path term is load-bearing. */ rule CVE_2026_60004_diffpatch_hook_patch_content { meta: description = "Git patch (or the JSON request carrying it) that installs an executable hook through the Gitea diffpatch API - CVE-2026-60004 ATTEMPT artefact. Also matches the vendor advisory PoC copy and the byte-identical patch on PATCHED hosts: it proves the bytes are present, never that they ran." author = "Xpectra Security Research" date = "2026-08-27" reference = "https://github.com/go-gitea/gitea/security/advisories/GHSA-rcr6-4jqh-j84m" cve = "CVE-2026-60004" stage = "attempt" severity = "high" strings: // In the JSON body of this endpoint newlines are the two bytes 5c 6e, so // every marker below appears as literal ASCII on the wire and on disk. $diff = "diff --git a/hooks/" ascii wide $mode = "new file mode 100755" ascii wide $tgt = "+++ b/hooks/" ascii wide $idx = "index 0000000000000000000000000000000000000000" ascii wide $sh = "#!/bin/sh" ascii $bash = "#!/bin/bash" ascii // endpoint locator, present when the artefact is a captured request $api = "/diffpatch" ascii $hook1 = "hooks/post-index-change" ascii $hook2 = "hooks/pre-push" ascii $hook3 = "hooks/post-receive" ascii $hook4 = "hooks/reference-transaction" ascii condition: // two diff-shaped markers make this a patch and not a plain shell script: // a stock hook file (shebang + the word "hooks") cannot reach 2 of them ((2 of ($diff, $mode, $tgt, $idx)) or ($api and $mode)) and (any of ($sh, $bash) or any of ($hook1, $hook2, $hook3, $hook4)) } rule CVE_2026_60004_materialised_canary_hook { meta: description = "The materialised canary hook from OUR reproduction (and the vendor PoC shape): a shell hook that fingerprints its own execution - parent cmdline from /proc, process tree, and an absolute canary write. Matches PoC-shaped payloads only; a bespoke attacker hook will not match, which is why the process-lineage Sigma rule is the primary execution signal." author = "Xpectra Security Research" date = "2026-08-27" reference = "https://github.com/go-gitea/gitea/security/advisories/GHSA-rcr6-4jqh-j84m" cve = "CVE-2026-60004" stage = "execution-artefact" severity = "high" strings: $sheb = "#!/bin/sh" ascii $c1 = "CANARY_EXEC_OK" ascii $c2 = "cve-2026-60004" ascii $c3 = "nonce=" ascii $p1 = "/proc/$$/cmdline" ascii $p2 = "/proc/$PPID/cmdline" ascii $ps = "ps -o pid,ppid" ascii $cwd = "git_dir_env=" ascii $red = "readlink -f" ascii condition: $sheb at 0 and 3 of ($c*, $p*, $ps, $cwd, $red) } rule CVE_2026_60004_hook_in_temp_upload_clone { meta: description = "A shell-shaped hook file whose PATH is inside Gitea's per-request temp clone (TMPDIR/local-repo/upload.git*/hooks/*). Behaviour-shaped: this path never appears on a healthy instance and never appears at all on a patched one, because 1.27.1 clones non-bare. Needs the path external variable, e.g. yara -p path=\"$PWD\" ..." author = "Xpectra Security Research" date = "2026-08-27" reference = "https://github.com/go-gitea/gitea/security/advisories/GHSA-rcr6-4jqh-j84m" cve = "CVE-2026-60004" stage = "behaviour-artefact" severity = "critical" strings: // NOT "#!/bin/": Gitea's own hook scripts start with `#!/usr/bin/env bash` // (measured on the target container), and the very file that proves this // rule's path logic is one of them. "script whose first two bytes are a // shebang" is the honest definition - the load-bearing term is the path. // Syntax note (measured on yara 4.5.8): the offset belongs in the // condition ("$sheb at 0"), NOT in the string definition - "$s = "x" at 0" // is a syntax error there. $sheb = "#!" ascii condition: // `path` is an external variable supplied per file by the harness // (yara -d path=...). YARA 4.5.8 raises "undefined identifier" when the // variable is not passed at all (measured), so the harness always passes // it - empty string when the real path is unknown - and the rule // self-silences on the empty value. path != "" and path matches /local-repo[\/]upload\.git[0-9]+[\/]hooks[\/]/ and $sheb at 0 }