Commit 82208dc
harden(danger): close shell-command classifier evasion vectors
The risk classifier is the approval gate's first line of defense, so it
must assume a prompt-injected agent is actively trying to disguise a
dangerous command as harmless. A review surfaced several bypasses where
a destructive/exfiltrating command under-classified to safe/local_write
(i.e. ran without a prompt). This closes them in layers:
Tokenizer
- Quote boundaries are no longer word boundaries: r""m, "rm", r''m all
resolve to `rm` again (empty/adjacent quotes used to split the verb).
Structural decomposition
- Every pipe stage is classified, not just the head command, so
`true | dd of=/dev/sda`, `: | wget … -O /tmp/x` and
`echo x | sudo rm -rf /home` are seen for what their later stages do.
Wrapper unwrapping
- Leading exec wrappers (env, xargs, nohup, nice, setsid, timeout, …)
are stripped so the real command is classified; sudo/doas/pkexec set a
system_write floor and let the inner command escalate (sudo rm -rf /var
→ destructive, instead of being masked as system_write).
Verb-independent resource scanning
- /dev/tcp and /dev/udp (reverse-shell channels) → network_egress.
- Reads/writes of sensitive credential paths (~/.ssh, /etc/shadow,
~/.aws/credentials, /proc/self/environ, …) → system_write.
Payload re-classification & normalisation
- bash/sh -c '…' payloads and <(…)/>(…) process substitutions are
re-classified (a shell given anything to execute → code_execution).
- New normalisation passes: ANSI-C $'\x72\x6d', brace expansion {rm,-rf,/}.
Detection coverage
- rm: robust recursive/force flag parsing (-rfv, -Rf, --recursive
--force) and relative wipe targets (~, $HOME, *, ., ..).
- dd: broadened raw block-device list (vd/hd/xvd/mmcblk/disk/loop/dm).
- network: socat, rclone, dig/nslookup/host/drill, aria2c/axel/httpie.
- code exec: source/., npx/bunx/uvx/pipx, pnpm|yarn dlx, uv run,
find -exec.
- install: pnpm/yarn/bun/apk add|install.
The package doc now states the threat model, the layered design, and the
explicit limitations (variable indirection, dynamic construction,
non-enumerated transforms) — this is defence-in-depth, not a sandbox, so
it errs toward over-classification (an extra prompt) over silent misses.
One existing expectation updated: `sudo rm -rf /var/log` is now
destructive (was system_write) — the more accurate, more secure class.
New hardening_test.go pins each closed vector and guards benign commands
against over-classification. Full suite green; go vet clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent 681bcd9 commit 82208dc
3 files changed
Lines changed: 762 additions & 50 deletions
0 commit comments