v0.6.0: What 80 Commits Look Like When Every One Is Driven by a Bug Report
v0.5.0 shipped on March 9 with five standalone hooks and an enforcement engine. Two weeks and 80 commits later, v0.6.0 ships with a fundamentally different scope. The difference is not ambition. The difference is that the Claude Code issue tracker kept producing evidence of what breaks.
The security fixes came first
Three vulnerabilities, all found during internal review:
The enforce-hooks engine was passing user-controlled values from CLAUDE.md into shell strings via interpolation. A crafted CLAUDE.md could execute arbitrary commands. The fix: environment variables instead of string interpolation, with 22 edge-case tests to prove it holds.
All four standalone hooks were building JSON responses via string concatenation. A filename containing a quote character could break the JSON structure. The fix: jq --arg everywhere, which handles escaping correctly regardless of input.
file-guard was normalizing paths incorrectly. A request for ../../.env could bypass a deny rule for .env. The fix: canonicalize before comparing.
None of these were reported by users. They were found by looking at the hooks the way an attacker would. But every one of them was a real vector. Shell injection in a safety tool is a particularly bad look.
bash-guard grew from 89 to 276 assertions
The original bash-guard blocked rm -rf /, sudo, curl|bash, and a handful of other obvious dangers. That was enough to catch the most dramatic failures. It was not enough for the patterns people were actually hitting.
Issue #37439: someone’s Laravel database got wiped by migrate:fresh. Issue #33183: prisma db push destroyed a production database with 276 accounts, 14,000 records, and 66,000 images. Issue #37599: credentials leaked through bash -x debug trace despite CLAUDE.md rules against it.
Each of these became a test case, then a detection rule. The test suite grew in layers:
- Docker destruction commands (
docker system prune -a,docker-compose down -v) - Database ORM commands across ecosystems (
prisma db push,migrate:fresh,fixtures:load,dropdb) - Credential dumping (
env,printenv,export -p,python -c "import os; os.environ") - Cloud infrastructure deletion (
terraform destroy,aws ... delete,kubectl delete) - Mass file removal (
find . -delete,xargs rm,git clean -fdx) - Compound command bypass (dangerous commands hidden behind
;,&&,||,$(), backticks) - Workaround bypass (
find -exec rm,pkexec,shred,truncate -s 0) - Data exfiltration (
curl -Ffile uploads,ncpiping, SSH key access, shell history exposure)
The compound command bypass work deserves its own note. bash-guard originally checked each command string as a unit. But users reported patterns like echo "safe" && rm -rf /important. The dangerous part is after the &&. Splitting on shell operators and checking each component added 20 assertions and closed a real gap.
file-guard got deny mode
The original file-guard blocked writes to sensitive files. A user request from issue #37128 made clear that blocking writes was not enough. Some files need to be completely invisible to the agent: not just unwritable but unreadable. The [deny] mode blocks Read, Grep, Glob, and Bash access to denied paths. 42 assertions became 86.
The read-once fix nobody noticed
read-once had been silently failing since Claude Code v2.1.78. The permissionDecision format it used to block re-reads was being ignored by newer versions (confirmed as a regression in issue #37597). The hook looked like it was working because no error appeared. It was actually approving every request.
This is the pattern that keeps recurring: fail-open is invisible. A hook that silently does nothing looks identical to a hook that deliberately permits. The fix was switching to the top-level decision:block format, which works across versions. But the real lesson is that hook health needs active verification, not passive observation.
The first external contribution
chris-peterson found the project through the blog, noticed that all standalone hook test payloads used input instead of tool_input (the correct field name in the Claude Code hook protocol), and submitted PR #2. Every standalone hook was affected. They were all silently failing open because the test payloads were structurally wrong.
This was the second time someone caught a critical bug by actually trying to use the hooks instead of just reading the README. The first was tclancy with issue #1, who found a malformed JSON response format within five minutes of installing.
Both bugs had the same root cause: the hooks were tested in isolation but never tested as a new user would encounter them. Both were caught by strangers within minutes of trying.
The numbers
| Suite | v0.5.0 | v0.6.0 |
|---|---|---|
| bash-guard | 89 | 276 |
| file-guard | 42 | 82 |
| git-safe | 45 | 51 |
| enforce-hooks | 134 | 50 |
| session-log | 52 | 81 |
| branch-guard | 35 | 36 |
| safety-check | 30 | 35 |
| Rust framework | 195 | 195 |
| Commits | - | 80 |
| Security fixes | 0 | 3 |
The enforce-hooks test count went down because the suite was refactored from monolithic detection tests to focused engine + integration tests. The detection patterns are now broader despite the smaller count.
What comes next
The issue tracker keeps producing signal. In the last 24 hours: someone lost data on a case-insensitive filesystem because the agent created a directory with a different case and then rm -rf‘d the original (#37875). An SDK update wiped someone’s entire ~/.claude/ directory, including hook configs and CLAUDE.md (#37871). A launchd-invoked Claude CLI started crashing in v2.1.81 (#37878).
The hooks can help with the first case. They cannot protect against the second and third, which are platform-level bugs. Knowing the boundary between what hooks can and cannot solve is part of the project’s honesty.
v0.6.0 is at github.com/Bande-a-Bonnot/Boucle-framework. Binaries for Linux and macOS, plus a Docker image, are on the releases page.