[Windows] Buffered keypress auto-approves plan/permission prompts after window switch or login

Status Closed — not planned
Maintainer reply None cached
Activity 5 comments · opened Jun 15, 2026 · closed Sep 2, 2026

Environment: Windows 11, Claude Code VSCode extension, claude-sonnet-4-6

Steps to reproduce:

  1. Have a plan-mode approval prompt or permission dialog active in Claude Code
  2. Switch to another Windows application (or lock/unlock the screen)
  3. Return to Claude Code — a buffered Enter keypress auto-approves the prompt without user review

Expected: Approval prompts should require deliberate user input after focus returns.

Actual: Claude Code treats the buffered keypress as an approval and immediately begins executing the plan/action.

Impact: Work executes without explicit user consent, which is especially problematic for destructive or hard-to-reverse operations (file edits, git commits, etc.).

View original on GitHub ↗

4 Comments

github-actions[bot] · 4 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/37820
  2. https://github.com/anthropics/claude-code/issues/37955
  3. https://github.com/anthropics/claude-code/issues/33988

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

jimmyjoe009 · 4 months ago

Not a duplicate. The steps to reproduce are different. After switching windows or after logging in to Windows. The plan is auto approved.

yurukusa · 4 months ago

The destructive-operation angle has a defense-in-depth mitigation worth knowing, even though the real fix is upstream (focus-return shouldn't consume a buffered keypress as approval).
**A PreToolUse hook gates the tool call before the interactive prompt, so a stray buffered keypress can't approve past it. When a tool is about to run, PreToolUse hooks evaluate the resolved command first; a hook returning a deny decision blocks the call and no approval prompt is shown at all**. That ordering is what makes it robust here: for the destructive cases you call out (rm -rf, git push to main, git reset --hard, writes outside the repo), a deny-hook on those patterns blocks them outright — so there is no prompt left for a buffered Enter to auto-approve.
In other words: the interactive prompt is a UI gate (defeatable by input buffering, as you found); a hook is a programmatic gate on the actual command string (not defeatable by a stray keypress). It doesn't fix the buffering bug, but it removes the "destructive op runs without consent" consequence for the patterns you encode.
Minimal DIY version — a PreToolUse matcher on Bash that denies your irreversible patterns:

// ~/.claude/settings.json
{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{ "type": "command", "command": "jq -r '.tool_input.command' | grep -Eq 'rm -rf|git reset --hard|git push.*(main|master)' && { echo 'blocked: irreversible op' >&2; exit 2; } || exit 0" }]
    }]
  }
}

(exit 2 from a PreToolUse hook denies the call.) If you'd rather not hand-maintain the pattern list, npx cc-safe-setup installs a ready set of these deny-hooks at the user level — free, only needs jq.
The upstream fix is still the right outcome: a pending plan-mode or permission dialog shouldn't accept a keypress buffered before focus returned. But encoding your destructive operations as hook denies means a buffered Enter can't trigger them in the meantime.

BGMLAI · 3 months ago

This needs an input-freshness boundary in the approval UI. Key events queued before the prompt becomes visible or before the window regains focus should be discarded; approval should require a new key-down/key-up sequence after the dialog activation epoch. For high-impact actions, a second distinct gesture or typed confirmation would further prevent accidental acceptance. This is worth testing with focus loss, auth redirects, key repeat, and buffered terminal input.

Showing cached comments. Read the full discussion on GitHub ↗