claude-code - 💡(How to fix) Fix [BUG] PreToolUse hook is not invoked after a static ask rule for the same command pattern receives session-level approval [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

Error Messages/Logs

Root Cause

Root cause: When a static ask rule gets session-approved, Claude Code bypasses the PreToolUse hook for all subsequent matching commands. The hook's deny output is never reached and so this is essentially a serious safety/security flaw in how this is processed.

Fix Action

Fixed

RAW_BUFFERClick to expand / collapse

Preflight Checklist

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

What's Wrong?

PreToolUse hook is not invoked after a static ask rule for the same command pattern receives session-level approval

Expected: Hook should always fire on PreToolUse regardless of static rule state — the hook's permissionDecision should be evaluated independently, especially for deny decisions which must not be suppressible by a prior session approval.

What Should Happen?

Expected: Hook should always fire on PreToolUse regardless of static rule state — the hook's permissionDecision should be evaluated independently, especially for deny decisions which must not be suppressible by a prior session approval.

Actual: Once Bash(docker --host:*) was session-approved via the ask prompt, subsequent docker --host ... rm and docker --host ... rmi commands bypassed the hook entirely (no log entries written, no deny enforced).

Why it matters: A deny from a hook should be unconditional — a session approval of a broad pattern like docker --host:* should not be able to whitelist destructive subcommands that the hook is explicitly denying.

Reproduction: Add a broad ask pattern + a PreToolUse hook that denies a subset of matching commands → approve the ask prompt once → subsequent deny-eligible commands run freely.

Essentially the json configs should be independent of hooks

Error Messages/Logs

Steps to Reproduce

Minimal repro for Claude Code hook bypass bug:

  1. Create a PreToolUse hook (~/.claude/hooks/guard.py):

#!/usr/bin/env python3
import json, sys, shlex

data = json.load(sys.stdin)
command = data.get('tool_input', {}).get('command', '').strip()

try:
tokens = shlex.split(command)
except ValueError:
sys.exit(0)

Skip global flags to find real subcommand

i = 1 while i < len(tokens) and tokens[i].startswith('-'):
i += 2 if tokens[i] in ('--host', '-H') and i+1 < len(tokens) else 1

subcommand = tokens[i] if i < len(tokens) else None

if subcommand in ('rm', 'rmi'):
print(json.dumps({'hookSpecificOutput': {'hookEventName': 'PreToolUse', 'permissionDecision': 'deny', 'permissionDecisionReason': 'guard: destructive'}}))

sys.exit(0)

  1. Register it in ~/.claude/settings.json:
    {
    "hooks": {
    "PreToolUse": [{"matcher": "Bash", "hooks": [{"type": "command", "command": "python3 ~/.claude/hooks/guard.py"}]}]
    },
    "permissions": {
    "ask": ["Bash(docker --host:*)"], "deny": []
    }
    }

  2. Reproduce:

Step A — trigger the ask prompt and APPROVE it:

docker --host unix:///var/run/docker.sock ps

Step B — now try a destructive command:

docker --host unix:///var/run/docker.sock rm <any-stopped-container>

Expected: Hook fires, deny blocks the command.
Actual: Hook is not invoked. Command reaches the Docker daemon.

Observable proof: Add open('/tmp/hook.log', 'a').write(command + '\n') to the hook — no log entry appears for step B.

Claude Model

Sonnet (default)

Is this a regression?

No, this never worked

Last Working Version

No response

Claude Code Version

2.1.87 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

I think this is a design issue at the end of the day. The claude.md and json ask/deny/allow should not override an independent hook as that is a different layer of safety unless that specific hook is explicitly overriden -

Root cause: When a static ask rule gets session-approved, Claude Code bypasses the PreToolUse hook for all subsequent matching commands. The hook's deny output is never reached and so this is essentially a serious safety/security flaw in how this is processed.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING