mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-11 02:33:10 +08:00
Six classes of bypass in scripts/hooks/gateguard-fact-force.js DESTRUCTIVE_BASH regex, plus a separate false-positive class. Same shape of issue as the block-no-verify holes addressed in #1843: a single-regex shell parser can never cover the flag-order variations git and rm allow. Real bypasses observed locally (all ALLOW today, should BLOCK): git push -f origin main (short form of --force) git -c core.foo=bar reset --hard (intervening -c global) rm -fr /tmp/junk (reverse flag order) rm -r -f /tmp/junk (split flag form) git reset HEAD --hard (intervening ref token) git clean -fd (combined -f + -d flag) False positive observed locally (BLOCK today, should ALLOW): git commit -m "fix: rm -rf race in worker" (destructive phrase inside quoted message) Behavior fix that comes along: --force-if-includes is now exempted alongside --force-with-lease. Both are safety-checked variants; the previous regex used a negative lookahead that only spelled out --with-lease, so --force-if-includes blocked under the old code even though it is the safer-not-harder choice. Fix shape (mirrors block-no-verify #1843): - DESTRUCTIVE_SQL_DD regex kept for `drop table`, `delete from`, `truncate`, `dd if=` — these are stable keyword phrases. Quoted strings are stripped before the regex runs so the phrase is not matched inside a commit message body. - isDestructiveBash() tokenizes the command into segments at unquoted ; | & boundaries, then per segment: * isDestructiveRm — detects `rm` with both r and f set across combined or split flag tokens. * isDestructiveGit — finds the git subcommand after skipping global options (-c key=val, -C path, --git-dir=, etc.), then handles reset, checkout --, clean -f*, push --force (with --force-with-lease / --force-if-includes exemption), commit --amend, and rm -r* preservation. - Command tokens go through commandBasename() so /usr/bin/rm, rm.exe, and RM all normalize to "rm". Tests (+10 in tests/hooks/gateguard-fact-force.test.js): Bypass-now-blocked (7): - denies short-form git push -f - denies git reset --hard with intervening -c global option - denies rm -fr (reverse flag order) - denies rm -r -f (split flag form) - denies git reset HEAD --hard - denies git clean -fd - denies destructive command in second chained segment False-positive-now-allowed (3): - allows destructive phrase inside `-m` commit message (rm -rf) - allows SQL phrase inside `-m` commit message (drop table) - allows --force-if-includes as a safety-checked variant Local verification: yarn lint clean scripts/ci/validate-* (agents/commands/rules/skills/hooks/ install-manifests/no-personal-paths) pass node tests/run-all.js 2380/2380 pass Caveat (unrelated): yarn test still fails at check-unicode-safety on skills/windows-desktop-e2e/SKILL.md (U+2605) per #1843's caveat — independent of this change. Provenance: discovered during a security pass on ECC after PR #1843 (block-no-verify shell-words rewrite) landed. Same class of regex-based shell parser issue, same shape of fix. Refs #1843.