[DOCS] PreToolUse hook permissionDecision "allow" silently bypasses native permission system

Resolved 💬 4 comments Opened Feb 26, 2026 by MFRWDesign Closed Mar 26, 2026

Documentation Type

Missing documentation (feature not documented)

Documentation Location

https://docs.anthropic.com/en/docs/claude-code/hooks

Section/Topic

PreToolUse hook permissionDecision behavior — default allow bypasses native permission system

Current Documentation

The hooks documentation states that PreToolUse hooks can "approve or deny in place of" the permission system, and provides examples showing permissionDecision: "allow" and permissionDecision: "deny" as return values.

What's Wrong or Missing?

There is no warning that returning permissionDecision: "allow" as a default/fallthrough in a PreToolUse hook completely replaces the native permission system. This means the "Allow / Always allow / Deny" prompt is never shown for any tool call that passes the hook's checks.

A common pattern for security hooks looks like this:

case "$TOOL" in
    Bash)
        if <dangerous pattern>; then
            # output deny JSON
            exit 0
        fi
        ;;
esac

# Default: output allow JSON  <-- THIS BYPASSES PERMISSION PROMPTS
exit 0

The developer's intent: "block dangerous commands, let everything else through to the normal permission flow."

The actual effect: "block dangerous commands, explicitly approve everything else, skip the permission prompt entirely."

This has caused multiple reports of permissions not working: #22338, #25168 — likely the same root cause (PreToolUse hook with allow default path).

Suggested Improvement

  1. Add a prominent warning in the hooks documentation: If your PreToolUse hook returns permissionDecision: "allow" as a default/fallthrough, it will bypass the native permission prompt for ALL tools that pass your checks. If you only intend to block specific patterns, return no JSON output (just exit 0) for the non-blocked case — the app treats "exit 0, no JSON" as "hook has no opinion, proceed to native permission check."
  1. Consider a third permission decision: Something like permissionDecision: "passthrough" or "defer" that explicitly means "this hook has no opinion, proceed to the native permission system." Right now the only way to achieve this is the implicit behavior of returning no JSON, which is unintuitive and easy to get wrong.
  1. Update the PreToolUse hook examples to show the correct pattern for security-only hooks (deny on match, no output on non-match) vs full permission override hooks (explicit allow/deny for everything).

Impact

High - Prevents users from using a feature

Additional Context

  • Workaround confirmed: Replacing the default output_allow with a bare exit 0 (no JSON output) restores the native permission prompt. Verified on Claude Code v2.1.59, macOS.
  • Related issues: #22338 (git commands executed without permission prompt — user has PreToolUse hook, never found root cause), #25168 (Edit tool executed without approval — similar pattern)
  • Environment: Claude Code v2.1.59, macOS Darwin 24.5.0, Opus 4.6, Claude Max

View original on GitHub ↗

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