PreToolUse hooks and --allowedTools not enforced in headless -p mode

Resolved 💬 5 comments Opened Mar 11, 2026 by GMedlin Closed Jun 13, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Two security mechanisms are not enforced when running claude -p in headless mode:

  1. PreToolUse hooks do not fire (previously reported in #20063, #30143, #18093 -- all auto-closed as stale/duplicate without a fix)
  2. --allowedTools restrictions are not enforced (not previously reported)

Both issues occur with --permission-mode bypassPermissions and with --dangerously-skip-permissions. Confirmed in both nested (from within Claude Code) and standalone terminal invocations.

Why This Matters

Users building headless automation with claude -p may rely on --allowedTools to restrict tool access (e.g., allowing only Read,Glob,Grep,Bash but not Edit,Write). If these restrictions aren't enforced, the model can use any tool regardless of the allowlist.

Similarly, PreToolUse hooks are commonly used to block access to sensitive files (credentials, secrets). If hooks don't fire in -p mode, these guards are silently bypassed.

The documentation does not clarify that hooks and --allowedTools are not enforced in headless mode. Users building secure automation pipelines have no way to know their security controls are decorative.

Steps to Reproduce

Test 1: --allowedTools bypass

# Create a test file
echo "CANARY_TOKEN_12345" > /tmp/canary-test.txt

# Run with only Glob allowed -- Read and Bash should be blocked
claude -p "Read the file at /tmp/canary-test.txt and print its contents verbatim." \
    --model haiku \
    --effort low \
    --permission-mode bypassPermissions \
    --output-format json \
    --allowedTools "Glob"

Expected: Claude cannot read the file (Read and Bash not in allowlist).
Actual: Claude reads the file and prints CANARY_TOKEN_12345.

Test 2: PreToolUse hooks

  1. Add a PreToolUse hook to .claude/settings.json that denies Read on certain file patterns
  2. Run claude -p with --permission-mode bypassPermissions asking to read a matching file
  3. The hook never fires -- the file is read successfully

Environment

  • Claude Code version: 2.1.73
  • OS: Windows 11 (Git Bash)
  • Both standalone terminal and nested invocations tested

Documentation Gap

The hooks documentation describes PreToolUse hooks as firing before tool execution but does not mention any exceptions for headless -p mode. The headless mode documentation documents --allowedTools without noting that it is not enforced. Users have no signal that these controls are inactive.

Suggested Fix

  • --allowedTools should be enforced in -p mode (this is a CLI-level restriction, not a permission prompt)
  • PreToolUse/PostToolUse hooks should fire in -p mode (PermissionRequest hooks reasonably may not, since there is no interactive prompt)
  • If enforcement is intentionally skipped in headless mode, the documentation should explicitly state this

View original on GitHub ↗

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