[BUG] --dangerously-skip-permissions resets mid-session when PreToolUse hooks are configured

Resolved 💬 3 comments Opened Mar 23, 2026 by backviet Closed May 1, 2026

Preflight Checklist

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

Summary

When --dangerously-skip-permissions is active and PreToolUse hooks are configured in settings.json, the permission mode resets to normal mid-session — suddenly requiring manual approval for every tool call. The session cannot recover without restart.

Related Issues

  • #1498 — Same symptom reported since v1.0.x, confirmed still occurring at v1.0.58+, issue locked
  • #12176 — PermissionRequest hook race condition (related but different hook type)
  • #12261 — "Dangerously skip permissions doesn't dangerously skip permissions"

Environment

  • Claude Code Version: 2.1.81
  • Platform: macOS (Darwin 25.3.0)
  • Shell: zsh
  • Node.js: 22.x

Steps to Reproduce

  1. Configure PreToolUse hooks in ~/.claude/settings.json:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{
          "type": "command",
          "command": "node \".claude/qk/hooks/dangerous-command-blocker.cjs\"",
          "timeout": 5
        }]
      },
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [{
          "type": "command",
          "command": "node \".claude/qk/hooks/file-boundary-guard.cjs\"",
          "timeout": 5
        }]
      }
    ]
  }
}
  1. Start Claude Code: claude --dangerously-skip-permissions
  2. Work normally — tools execute without prompts
  3. After some time (varies: 30min–2hrs), permission prompts suddenly appear for ALL tool calls
  4. Even previously auto-approved tools (Read, Glob, Grep) now require confirmation
  5. Session is unrecoverable — must restart

Hook Output Protocol (verified correct)

Our hooks follow the documented protocol:

// Allow: silent exit
process.exit(0);

// Block (ask user): stdout JSON + exit 0
process.stdout.write(JSON.stringify({
  hookSpecificOutput: {
    hookEventName: 'PreToolUse',
    permissionDecision: 'ask',
    permissionDecisionReason: '...',
  },
}));
process.exit(0);
  • ✅ Always exit(0) — never exit(2)
  • ✅ Always stdout — never stderr
  • ✅ Outer try/catch wraps entire hook → fail-open on crash
  • ✅ TTY detection → skip if no pipe (prevents blocking)
  • ✅ Hooks only fire on matching tools (Bash for blocker, Write/Edit for guard)

What We've Tried

| Attempt | Result |
|---------|--------|
| Changed exit(2) + stderr → exit(0) + stdout JSON | Improved but not fixed |
| Changed permissionDecision: 'deny''ask' | No change |
| Added hookEventName: 'PreToolUse' | No change |
| Added fail-open crash wrapper | No change |
| Set hook timeout to 5s | No change |
| Disabled hooks (qkit guard off) | ✅ Fixes it — confirms hooks are the trigger |

Key Observation

Disabling PreToolUse hooks completely prevents the issue. This confirms the permission reset is triggered by hook execution, not by other session factors.

Expected Behavior

--dangerously-skip-permissions should persist for the entire session regardless of PreToolUse hook output. Hooks returning permissionDecision: 'ask' should prompt for that specific tool call only, without resetting the global permission mode.

Actual Behavior

At some point during the session, the global permission mode resets from "bypass" to "normal", requiring approval for ALL subsequent tool calls — including tools that have no PreToolUse hooks configured.

Questions for the Team

  1. Does permissionDecision: 'ask' from a PreToolUse hook interact with --dangerously-skip-permissions state? Is this by design?
  2. Is there a known race condition where hook timeout (5s) could cause permission state corruption?
  3. Should PreToolUse hooks be completely ignored when --dangerously-skip-permissions is active?

View original on GitHub ↗

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