# git-guard shim — C215 fork-bomb containment, verified in the danger lab

Date: 2026-08-08 · Lab: debian1 `dangerlab`, slot1 (`192.168.122.101`), four single-use clones
Proof: `modules/workstation/claude/tests/git-guard-forkbomb.dangerlab.sh`
Run it: `bash modules/workstation/claude/tests/run-in-lab.sh git-guard-forkbomb.dangerlab.sh 420`

`tests/run-all.sh` collects `*.dangerlab.sh` as well, so off the lab guest it names this suite
in its refusal instead of leaving it silently unrun.

Question answered: does `_git-guard-shim.sh` still contain the fork-bomb class of
[C215](../../../0%20DOCS/2026-08-07-incident-git-shim-fork-bomb-paralysis.md)? Containment was the
disposable clone — destroyed after every run. `ulimit -u` in the proof is an instrument that makes
the red terminate readably, not a safety control.

## The mechanism the red had to reproduce

The shim at `544366d3` resolved "the real git" by walking `PATH`, skipping only its own directory.
A second copy of the shim anywhere else on `PATH` became its real git and was assigned to
`WT_GIT_BIN`. `wt_main_root` then runs

```
"$WT_GIT_BIN" -C <dir> rev-parse --path-format=absolute --git-common-dir
```

inside a command substitution — a **fork**, not an exec — and the child is another shim that forks
its own classification call. That fanout, not the `exec "$real"` tail, is what reached 14,200
processes. A red that spun one process would not be this bug.

## Measured

Fixture `tests/fixtures/git-guard-shim-544366d3.sh`, md5 `bc6686967bcf7c4792b56729e6184e5c` —
asserted at runtime, because a drifted fixture would silently stop being the C215 body.
Current body md5 `4e1488076937b7a8cbca95898bb45ee5`.

| case | body | fixture | result |
|---|---|---|---|
| 1 RED | `544366d3` | two installs on one `PATH` | `rc=124` procs **140 → 291** (cap 158), 25381 classification calls sampled |
| 2 | current | same hostile `PATH` | `rc=0` procs 125 → 125, real `git status` ran |
| 3 | current | same hostile `PATH`, `restore .` | `rc=77`, guard still blocks |
| 4 | current | pin points at a copy of the shim | `rc=78` procs 125 → 125 |

Case 1, verbatim, matching the command the incident observed ~90× concurrently:

```
bash /tmp/ggfb-o1LE/redB/bin/git -C /tmp/ggfb-o1LE/repo rev-parse --path-format=absolute --git-common-dir
```

The storm saturated `RLIMIT_NPROC` in under 20 s. Sampling is fork-free (bash globs over `/proc`,
a fifo for the tick) precisely because `RLIMIT_NPROC` is per-UID: anything that forks to observe
the storm dies with it. That is C215's paralysis in miniature.

## What the run found — case 4 was red before this change

The current body defeats PATH poisoning by never reading `PATH`; it resolves only the install-time
pin. But `shim_pin_read` did not check whether the *pin* named a shim. With a poisoned pin the
first invocation resolved a shim as its real git, cleared the depth counter at the hand-off, and
the pair exec'd each other forever: `rc=124`, no fork growth, **git never returns**. Section I of
`git-guard-shim.test.sh` asserted `79` and had been failing in the lab for exactly this reason.

Not a fork bomb — a permanent hang on the most-invoked command on the machine, which by the
incident's own "paralysis is worse than death" finding is the same class of outcome.

Fixed here: `shim_pin_read` skips a pinned target for which `shim_is_shim` holds, so a poisoned pin
is unusable like an absent one — exit 78 naming `install-git-guard-real`. The depth bound stays as
the backstop and is now asserted directly (case J of `git-guard-shim.test.sh`).

## Suites after the change (both in the lab)

`git-guard-forkbomb.dangerlab.sh` PASS=4 FAIL=0 · `git-guard-shim.test.sh` PASS=10 FAIL=0

Clones: four created, four destroyed. Post-run `dangerlab slots` reported all four
`domain=undefined owner=free overlay=no`, and the template verified against its sha256 pin.

Unrelated pre-existing red, reproduced on `main` at `49cc07d6` and untouched here:
`cpu-guard-script-body.test.sh` routes `pnpm install` and `pnpm install-browsers` REMOTE where it
wants LOCAL (2 failures).
