You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
hooks/gates/irrecoverable.py allows four destructive shapes that it should deny. I reproduced each against develop by piping a PreToolUse payload into hooks/gates/irrecoverable.sh, with MH_GATE_JOURNAL_PATH pointed at a scratch file:
command
exit
expected
rm -rf build
2 (deny)
2
eval "rm -rf build"
2 (deny)
2
rm${IFS}-rf build
0
2
X=rm; $X -rf build
0
2
mkfs.ext4 /dev/sda1
0
2
chmod -R 777 /
0
2
The first two rows are controls. A grep of irrecoverable.py finds no IFS, mkfs or chmod handling.
These were found by reading third-party Claude Code mods (aitmpl security/jev-auto-moderules.ts:407-560, security/block-destructive-commands) during the #323 research. jev-auto-mode reads each command part twice, as written and as the shell runs it: quotes dropped, $IFS read as a space, wrappers stripped, same-line assignments read back. A program known only at run time ($X, source) gets an "ask" floor instead of a pass.
Fix direction
Normalize $IFS / ${IFS} (and $IFS$9-style forms) to a space before tokenizing.
Read back same-statement and earlier same-line assignments (X=rm; $X …, X=rm && $X …) before the verb check. Where the verb stays unknown ($X with no visible assignment, source <file>), apply an ask floor rather than allow, matching the existing ask path used for gh pr merge.
Add patterns: mkfs* / mkfs.*, chmod with 777 or a+rwx on /, ~ or -R, and rm --no-preserve-root.
Related: #49 (closed) was the same indirection class in convergence-merge-gate.sh.
Acceptance: the four rows deny (or ask, for the opaque-variable case) in tests/. Each new test is red on current develop. Existing gate tests stay green.
Activity
Merge pull request #376 from wasikarn/claude/gate-336-irrecoverable