Purge wave 3: the baseline moves, two guards go
Divergence purge #3835, PR 5 of 6 · 2026-08-31
Why "un-disableable hook" was the weaker guarantee
SECURITY_HOOKS registry "Cannot disable security-critical hook": assertCanToggle() throws
what it protected against a user editing .claude/hook-overrides.json to switch a guard off
what it could NOT do run when the user passes --dangerously-skip-permissions (ASK tiers stood down), or
when the plugin bundle failed to load (#3817), or when CC's own permission
layer decided first
permissions.deny in the enforced by CC before any hook runs; measured to hold under
operator's settings --dangerously-skip-permissions with no hooks loaded (canary probe, #3836)
So the baseline commit comes first, on its own. dangerous-command-blocker, file-guard and git-validator leave the registry (6 to 3), the P0 table and the runner's set, with the rationale in the file header. The deletions ride behind it in the same PR.
Deleted in this wave
| hook | native replacement | guardrail before deleting |
|---|---|---|
file-guard (both halves: protected patterns DENY, oversized-file ASK) | Edit()/Write() deny rules in the operator scope; a Read() deny also hides the file from Glob and Grep since 2.1.162 | payload v2 carries every PROTECTED_PATTERN (credentials.json, secrets.json, *.pem, private.key, id_rsa, id_ed25519, .husky/); the size ASK opinion is dropped, loss accepted |
credential-read-guard (the one hooks.json entry: 176 to 175) | the same Read() rules, delivered by setup 3.6, audited by doctor | this hook existed precisely because plugin-shipped rules were inert; the register said "delete after probe", and the probe is a CI step now |
The security suite keeps gating, in the tripwire shape
before test-path-traversal.sh "file-guard denies .env, resolves symlinks, tolerates dangling links"
after test-path-traversal.sh "file-guard.ts is ABSENT, not in the entries map, AND every pattern it
denied is an Edit+Write rule in the payload, AND the canary probe is
wired into CI" -> a revived hook OR a lost rule fails here
same test-symlink-attacks.sh, test-unicode-attacks.sh section 2, test-additional-security.sh probes
history the full old contracts sit at the commit before this wave
Gates at commit
| hooks suite | 7504 passed, 2 skipped; entries-map pin 197 to 195 on this branch |
| security suite | 20/20, four files rewritten as tripwires |
| verdict probes | 16/16 (two file-guard/credential probes retired) |
| registry closure | PASS, zero grandfathered |
| unit / integration / hooks rosters | all green after the count re-stamp |