Adversarial Study
Adversarial Benchmark of .git/ Pillagers
Companion to Benchmark. Measures how each pillager holds up when the served.git/ is malicious.
Wang Yihang · updated Jul 12, 2026 · commit826a0a3
§1.Threat Model
We run each pillager against a series of maliciously-crafted.git/ directories, modeled after published research (justinsteven 2022, Driver Tom 2021) and well-known Git CVEs. A test is a FAIL if the malicious server attains code execution, arbitrary file write, or SSRF against the tool's container during recovery; PASS if the tool refused or contained the payload. Tools with unreported findings are anonymized as Tool A…F; the mapping is maintained internally until coordinated disclosure completes (see §5).
§2.Test Corpus
17 tests, drawn from public advisories and the Git CVE feed. Categories: RCE (remote code execution against the tool host), AFW (arbitrary file write outside the output directory), Info (information disclosure, e.g. SSRF), CVE (regression tests for Git CVEs that fire on git clone / checkout).
Table 4.Adversarial test corpus. CVE column lists upstream identifiers where available.
| Test | Category | Sev. | CVE | Description |
|---|---|---|---|---|
A1-FSMONITOR | RCE | H | — | core.fsmonitor in .git/config executes attacker command on any git operation (justinsteven 2022) |
A2-PAGER | RCE | M | — | core.pager in .git/config executes attacker command on git log / git show / git diff |
A3-SMUDGE-FILTER | RCE | H | — | filter.<name>.smudge in .git/config + .gitattributes filter=<name> on a tracked file executes attacker command on git checkout |
A4-DIFF-EXTERNAL | RCE | M | — | diff.external in .git/config executes attacker command on git diff |
A5-CORE-EDITOR | RCE | L | — | core.editor / sequence.editor in .git/config executes attacker command on git commit / rebase (uncommon for pillagers) |
B1-INDEX-TRAVERSAL | AFW | H | — | Crafted .git/index has entries with ../../ paths; git checkout / checkout-index writes blobs outside the repo (Driver Tom 2021) |
C1-HTML-TRAVERSAL | AFW | H | — | HTML directory listing with traversal anchor (<a href="../../canary/...">) lets a recursive pillager write outside its output directory (justinsteven 2022 second PoC) |
C2-REDIRECT-FILE | Info | M | — | Server responds to every request with 302 Location: file:///etc/passwd; a pillager that follows non-HTTP(S) redirects ends up reading local files |
C3-REDIRECT-SSRF | Info | L | — | Server redirects every request to http://127.0.0.1:12345/, an internal SSRF target; a sidecar listener on that port writes the canary if hit |
C4-ABSOLUTE-PATH-WRITE | AFW | H | — | HTML directory listing whose <a href> targets are server-controlled ABSOLUTE paths (leading `/`, `//`, encoded `%2f`, backslash roots) instead of relative `../` climbs: a recursive pillager that honours an absolute path writes outside its output directory. Sibling to C1 (relative traversal); the absolute targets are pointed at the mounted /canary so the escaping write is detectable (justinsteven 2022 / GHSA-hr3m-4qwq-3mgc corpus, Zac Wang 2026) |
D1-HEAD-REF-TRAVERSAL | Info | M | GHSA-hr3m-4qwq-3mgc | Crafted .git/HEAD with `ref: ../../canary/<bait>` coerces the pillager into reading a file outside its output directory; the 40-char hex inside that bait file then leaks back to the attacker as object-path GETs (existence oracle + hex-fragment exfiltration, GitHacker <= 1.1.7, Zac Wang 2026) |
E1-CVE-2025-48384 | CVE | H | CVE-2025-48384 | Submodule path containing carriage return in .gitmodules; on git clone --recursive, hook is written to attacker-controlled location (in-the-wild exploited 2025; Linux/macOS) |
E2-CVE-2024-32002 | CVE | H | CVE-2024-32002 | Submodule with case-insensitive name collision plus symlink writes a hook on git clone --recursive (vulnerable git versions on case-insensitive filesystems) |
E3-CVE-2018-11235 | CVE | M | CVE-2018-11235 | Submodule path containing ../ escapes $GIT_DIR/modules, allowing post-checkout hook execution (patched in modern git; tests fall back to PASS) |
E4-CVE-2023-29007 | CVE | M | CVE-2023-29007 | Submodule URL >1024 chars injects arbitrary git config sections (core.pager etc.) via 'git submodule sync/deinit' on patched git also blocked; here as regression |
E5-CVE-2017-1000117 | CVE | M | CVE-2017-1000117 | Submodule SSH URL of form 'ssh://-oProxyCommand=...' executes attacker command on git clone --recurse-submodules (patched in git ≥ 2.13.5) |
F2-LFS-SMUDGE | CVE | M | CVE-2021-21300 | Git LFS smudge filter with case-insensitive name + symlink writes a shell script the git wrapper executes on clone (vulnerable git-lfs versions on case-insensitive filesystems) |
§3.Results Summary
PASS rate per tool over the 17-test corpus. Higher is better — a PASS means the tool refused or contained the payload. Best in bold.
Table 5.Per-tool PASS rate across the full adversarial corpus. Best in bold.
| Tool | Version | PASS / Total | Rate |
|---|---|---|---|
| GitHacker | 1.1.10+local | 17 / 17 | 100.0% |
| Tool A | — | 15 / 17 | 88.2% |
| Tool B | — | 17 / 17 | 100.0% |
| Tool C | — | 17 / 17 | 100.0% |
| Tool D | — | 16 / 17 | 94.1% |
| Tool E | — | 16 / 17 | 94.1% |
| Tool F | — | 17 / 17 | 100.0% |
§4.Per-Test Matrix
PASS / FAIL grid per (test × tool). Every verdict is published; anonymity is enforced only at the tool name (Tool A…F), since the test corpus is already public research.
Table 6.Per-test verdict matrix. PASS = tool resisted the payload; FAIL = exploit succeeded.
| Test | Cat. | Sev. | GitHacker | Tool A | Tool B | Tool C | Tool D | Tool E | Tool F |
|---|---|---|---|---|---|---|---|---|---|
A1-FSMONITOR | RCE | H | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
A2-PAGER | RCE | M | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
A3-SMUDGE-FILTER | RCE | H | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
A4-DIFF-EXTERNAL | RCE | M | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
A5-CORE-EDITOR | RCE | L | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
B1-INDEX-TRAVERSAL | AFW | H | PASS | FAIL | PASS | PASS | PASS | PASS | PASS |
C1-HTML-TRAVERSAL | AFW | H | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
C2-REDIRECT-FILE | Info | M | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
C3-REDIRECT-SSRF | Info | L | PASS | FAIL | PASS | PASS | FAIL | FAIL | PASS |
C4-ABSOLUTE-PATH-WRITE | AFW | H | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
D1-HEAD-REF-TRAVERSAL | Info | M | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
E1-CVE-2025-48384 | CVE | H | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
E2-CVE-2024-32002 | CVE | H | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
E3-CVE-2018-11235 | CVE | M | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
E4-CVE-2023-29007 | CVE | M | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
E5-CVE-2017-1000117 | CVE | M | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
F2-LFS-SMUDGE | CVE | M | PASS | PASS | PASS | PASS | PASS | PASS | PASS |
§5.Disclosure Timeline
Each finding's coordinated-disclosure state, plotted across observation, vendor contact, and patch landing. Findings still under embargo do not appear here until we contact upstream.
Table 7.Disclosure tracker. Status terms follow standard coordinated-disclosure stages.
| ID | Test | Tool | Sev. | Status | First obs. | CVE |
|---|---|---|---|---|---|---|
DIS-2026-001 | C3-REDIRECT-SSRF | GitHacker | L | patched | 2026-05-27 | — |
DIS-2026-002 | A1-FSMONITOR | Tool C | H | confirmed | 2026-05-27 | — |
DIS-2026-003 | A1-FSMONITOR | Tool F | H | confirmed | 2026-05-27 | — |
DIS-2026-004 | B1-INDEX-TRAVERSAL | Tool A | H | confirmed | 2026-05-27 | — |
DIS-2026-005 | B1-INDEX-TRAVERSAL | Tool C | H | confirmed | 2026-05-27 | — |
DIS-2026-006 | B1-INDEX-TRAVERSAL | Tool F | H | confirmed | 2026-05-27 | — |
DIS-2026-007 | C3-REDIRECT-SSRF | Tool A | L | confirmed | 2026-05-27 | — |
DIS-2026-008 | C3-REDIRECT-SSRF | Tool D | L | confirmed | 2026-05-27 | — |
DIS-2026-009 | C3-REDIRECT-SSRF | Tool E | L | confirmed | 2026-05-27 | — |
§6.Anonymity Policy
8 findings are currently pre-disclosure. We publish the full verdict matrix and the disclosure tracker, but the affected tool names render asTool A…F until each upstream maintainer is contacted. The mapping is held in this repository's private disclosure tracker and is rotated forward — never reused — once a finding reaches disclosed. GitHacker is never anonymized in either direction.
References
- justinsteven.Various abuses of
core.fsmonitorin a directory's.git/config. 2022. github.com/justinsteven/advisories - Driver Tom.别想偷我源码:通用的针对源码泄露利用程序的反制. 2021. drivertom.blogspot.com
- Git project. Security advisories.github.com/git/git/security/advisories