claude-code - 💡(How to fix) Fix Auto-mode permission decider denies remediation-gated retries after PreToolUse hook denial [1 participants]

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…
GitHub stats
anthropics/claude-code#51676Fetched 2026-04-22 07:55:52
View on GitHub
Comments
0
Participants
1
Timeline
5
Reactions
0
Author
Participants
Timeline (top)
labeled ×5

Intent-aware gating vs shape-aware gating: the shape-aware version creates the bypass surface it's trying to prevent.

In defaultMode: auto with skipAutoPermissionPrompt: true, the permission decider pattern-matches prior tool call denied by a PreToolUse hook → same-intent retry as a bypass, even when the deny reason's remediation was completed between the two calls.

Root Cause

Intent-aware gating vs shape-aware gating: the shape-aware version creates the bypass surface it's trying to prevent.

In defaultMode: auto with skipAutoPermissionPrompt: true, the permission decider pattern-matches prior tool call denied by a PreToolUse hook → same-intent retry as a bypass, even when the deny reason's remediation was completed between the two calls.

Code Example

#!/usr/bin/env node
import { existsSync, writeFileSync, mkdirSync } from 'fs';
const marker = '/tmp/decider-repro/denied';
let raw = ''; for await (const c of process.stdin) raw += c;
const input = JSON.parse(raw);
if (input.tool_name === 'Bash' && !existsSync(marker)) {
  mkdirSync('/tmp/decider-repro', { recursive: true });
  writeFileSync(marker, '1');
  process.stdout.write(JSON.stringify({
    hookSpecificOutput: {
      hookEventName: 'PreToolUse',
      permissionDecision: 'deny',
      permissionDecisionReason: 'Read README.md first, then retry.',
    },
  }));
}
process.exit(0);

---

{
  "permissions": { "defaultMode": "auto" },
  "skipAutoPermissionPrompt": true,
  "skipDangerousModePermissionPrompt": true,
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{
        "type": "command",
        "command": "node ~/demo/deny-then-allow.mjs",
        "timeout": 5
      }]
    }]
  }
}
RAW_BUFFERClick to expand / collapse

Summary

Intent-aware gating vs shape-aware gating: the shape-aware version creates the bypass surface it's trying to prevent.

In defaultMode: auto with skipAutoPermissionPrompt: true, the permission decider pattern-matches prior tool call denied by a PreToolUse hook → same-intent retry as a bypass, even when the deny reason's remediation was completed between the two calls.

Minimal reproducer

~/demo/deny-then-allow.mjs:

#!/usr/bin/env node
import { existsSync, writeFileSync, mkdirSync } from 'fs';
const marker = '/tmp/decider-repro/denied';
let raw = ''; for await (const c of process.stdin) raw += c;
const input = JSON.parse(raw);
if (input.tool_name === 'Bash' && !existsSync(marker)) {
  mkdirSync('/tmp/decider-repro', { recursive: true });
  writeFileSync(marker, '1');
  process.stdout.write(JSON.stringify({
    hookSpecificOutput: {
      hookEventName: 'PreToolUse',
      permissionDecision: 'deny',
      permissionDecisionReason: 'Read README.md first, then retry.',
    },
  }));
}
process.exit(0);

~/.claude/settings.json (minimal):

{
  "permissions": { "defaultMode": "auto" },
  "skipAutoPermissionPrompt": true,
  "skipDangerousModePermissionPrompt": true,
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{
        "type": "command",
        "command": "node ~/demo/deny-then-allow.mjs",
        "timeout": 5
      }]
    }]
  }
}

Sequence:

  1. rm -rf /tmp/decider-repro && mkdir /tmp/test-repo && echo hi > /tmp/test-repo/README.md
  2. Ask Claude Code to run ls /tmp/test-repo. Hook denies with "Read README.md first, then retry."
  3. Ask Claude Code to Read /tmp/test-repo/README.md. Read succeeds.
  4. Ask Claude Code to retry ls /tmp/test-repo. Hook no longer denies (marker set). Auto-mode denies the retry with a reason about "retry after guard block bypass pattern" that does not reference the intervening Read.

Expected

Step 4 allowed. The hook's deny reason named the remediation ("Read README.md first"); the agent performed it; the retry should proceed.

Actual

Step 4 denied by auto-mode. Agents adapt by changing command shape (-F commit-msg-file for git commit, tool-swap EditBash, etc.) to slip the pattern matcher ... the exact behavior the pattern is meant to catch.

Requested fix

A Read of X.md after a deny telling the agent to read X.md should not cause the next tool call to be denied as a bypass. The mechanism is for you to determine.

Environment

  • Claude Code 2.1.116
  • macOS 26.2 (darwin 25.2.0)
  • ~/.claude/settings.json: "permissions": { "defaultMode": "auto" } + "skipAutoPermissionPrompt": true + "skipDangerousModePermissionPrompt": true. This combination activates the silent auto-mode decider that emits the denial reason referenced above.

extent analysis

TL;DR

The issue can be fixed by modifying the permission decider to recognize when a retry is legitimate after a remediation action has been taken, rather than treating it as a bypass attempt.

Guidance

  • Review the defaultMode: auto configuration in ~/.claude/settings.json to ensure it's correctly set up for auto-mode decisions.
  • Modify the permission decider pattern-matching logic to account for cases where a deny reason's remediation has been completed between two tool calls, allowing legitimate retries.
  • Consider adding a mechanism to track remediation actions taken after a deny, to inform the decision on subsequent tool calls.
  • Investigate the PreToolUse hook's behavior and how it interacts with the auto-mode decider, to ensure it's not inadvertently triggering bypass detections.

Example

No code example is provided due to the complexity of the issue and the need for a deeper understanding of the Claude Code's internal logic.

Notes

The fix may require changes to the Claude Code's internal logic or the configuration of the PreToolUse hook, and may involve adding additional tracking or state management to handle remediation actions and retries.

Recommendation

Apply a workaround by modifying the permission decider logic to recognize legitimate retries after remediation, as this is a more targeted solution than upgrading to a potentially non-existent fixed version.

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

claude-code - 💡(How to fix) Fix Auto-mode permission decider denies remediation-gated retries after PreToolUse hook denial [1 participants]