Subagents with bypassPermissions ignore PreToolUse hooks — unauthorized commands, wasted tokens

Resolved 💬 3 comments Opened Apr 5, 2026 by Gorocy Closed May 15, 2026

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)
  • just commands
  • python3 one-liners

None of these commands are on my allowlist. All should have been blocked.

Concrete Damage

  1. Unauthorized commits — 3 commits made to my repo without my approval. Had to review and assess each one.
  2. 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.
  3. Time wasted — Extra time spent discovering the bypass, reviewing unauthorized changes, cleaning up, and redoing the implementation correctly.
  4. 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)

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗