The pre-bash PreToolUse hook in .claude/helpers/hook-handler.cjs is a
security gate that refuses dangerous commands. In 3.6.30 it read the
wrong stdin field (`toolInput` object instead of `toolInput.command`
string), `.toLowerCase()` threw TypeError, the global safety-timer
try/catch swallowed it, and the handler printed misleading
"[OK] Command validated" while exiting 0 — letting `rm -rf /` through.
The bind-the-string fix already landed in alpha.39 via #1944. This
commit adds:
1. Belt-and-suspenders defensive coding — wrap with String(... || '')
so any future regression that re-binds command to null/undefined/an
object can no longer throw and silently exit 0.
2. New dedicated CI job `pre-bash-hook-smoke` (#2017) that drives real
Claude-Code-shaped PreToolUse JSON into BOTH handler copies and
fails on any of:
- dangerous command + exit 0 (the security bypass)
- "[OK] Command validated" on a dangerous input (misleading log)
- "[WARN] Hook X encountered an error" anywhere (silent-swallow)
Wired into witness-verify's needs:, so the gate now blocks publish.
3. Path filters extended: '**/.claude/helpers/hook-handler.cjs' triggers
the smoke whenever either handler copy changes.
Cases covered: dangerous rm -rf /, fork-bomb, format c:, null command
field (defensive), empty payload, snake_case tool_input.command shape
(the exact #2017 reproduction), innocuous ls -la.
Ships as 3.7.0-alpha.40 to all three packages.