Subagents with bypassPermissions ignore PreToolUse hooks — unauthorized commands, wasted tokens
Summary
When Claude Code dispatches subagents via the Agent tool with mode: "bypassPermissions", PreToolUse hooks are completely bypassed. Subagents execute arbitrary commands that the user explicitly blocked via a hook-based allowlist. This leads to:
- Unauthorized file modifications and git commits
- Wasted tokens on work that has to be undone
- User's security boundary rendered useless
My Setup
I have a PreToolUse hook enforcing a strict command allowlist:
# .claude/hooks/allowlist.sh — exits 2 (BLOCK) for anything not on the list
ALLOWED=(
"^cargo (build|test|check|clippy|run|fmt)"
"^cargo sqlx"
"^git (status|log|diff|show|branch)"
"^docker "
"^psql "
)
Only read-only git commands, cargo, docker, and psql are allowed. Commands like git add, git commit, rm, chmod, just, python3 are explicitly blocked.
What Happened
Claude dispatched 4+ subagents with mode: "bypassPermissions". These subagents freely ran:
git add+git commit(3 unauthorized commits)rm(deleted 7 files)chmod +x(changed file permissions)justcommandspython3one-liners
None of these commands are on my allowlist. All should have been blocked.
Concrete Damage
- Unauthorized commits — 3 commits made to my repo without my approval. Had to review and assess each one.
- Wasted tokens — Subagents created 7 bash scripts (~350 LOC), committed them, then the work had to be completely redone because the approach was wrong (should have been inline justfile recipes). The create-then-delete cycle burned tokens for nothing.
- Time wasted — Extra time spent discovering the bypass, reviewing unauthorized changes, cleaning up, and redoing the implementation correctly.
- False sense of security — I set up the allowlist hook specifically to control what Claude can do. It was silently bypassed with no warning.
Expected Behavior
PreToolUse hooks with exit 2 (BLOCK) should be enforced regardless of the agent's permission mode. The hook represents a user-defined security boundary.
bypassPermissions should bypass interactive permission prompts (the "allow this command?" dialog), NOT user-defined hooks.
Actual Behavior
bypassPermissions bypasses everything — including hooks. The user has no way to enforce command restrictions when subagents are involved.
Suggested Fix
- Separate "bypass interactive prompts" from "bypass hooks"
- Hooks with exit code 2 should ALWAYS block, in any mode, in any subagent
- At minimum: document this behavior clearly so users know their hooks are not a security boundary when subagents are dispatched
Environment
- Claude Code: latest (as of 2026-04-05)
- Model: Claude Opus 4.6 (1M context)
- OS: Linux (Manjaro)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗