DEV Community

Cover image for 6 Claude Code Permission Traps I Found Answering GitHub Issues This Week
Yurukusa
Yurukusa

Posted on • Edited on

6 Claude Code Permission Traps I Found Answering GitHub Issues This Week

My AI (Claude Code) answered 57 GitHub Issues this week about Claude Code permissions not working as expected. Here are the 6 patterns that keep tripping people up — and the hooks that fix them.

Trap 1: allow Cancels ask (17 Upvotes, 18 Comments)

{
  "permissions": {
    "allow": ["Bash(*)"],
    "ask": ["Bash(rm *)"]
  }
}
Enter fullscreen mode Exit fullscreen mode

Expected: safe commands auto-approve, rm asks first.
Actual: everything auto-approves. ask is silently ignored. (#6527)

Fix: A PreToolUse hook catches what ask misses:

#!/bin/bash
COMMAND=$(cat | jq -r '.tool_input.command // empty')
if echo "$COMMAND" | grep -qE 'rm\s+(-[rf]+\s+)*(\/|~|\.\./)'; then
    echo "BLOCKED: rm on sensitive path" >&2
    exit 2
fi
exit 0
Enter fullscreen mode Exit fullscreen mode

Trap 2: Trailing Wildcards Don't Match Zero Arguments

{ "permissions": { "allow": ["Bash(ssh * uptime *)"] } }
Enter fullscreen mode Exit fullscreen mode

ssh host uptime -s → allowed. ssh host uptimeprompts. The trailing * requires at least one character. (#36873)

Fix: Use regex (\s|$) in a hook — matches "space or end of string":

if echo "$COMMAND" | grep -qE '^\s*ssh\s+\S+\s+uptime(\s|$)'; then
    # auto-approve
fi
Enter fullscreen mode Exit fullscreen mode

Trap 3: Edit/Write Rules Ignored on Windows

Edit(.claude/**) in settings.json has no effect on Windows VS Code. Bash rules work fine — Edit/Write don't. (#36884)

Fix: A PermissionRequest hook bypasses the broken matcher:

TOOL=$(cat | jq -r '.tool_name // empty')
if [[ "$TOOL" == "Edit" || "$TOOL" == "Write" ]]; then
    jq -n '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","permissionDecision":"allow"}}'
fi
Enter fullscreen mode Exit fullscreen mode

Trap 4: Protected Directories Ignore bypassPermissions

Since v2.1.78, .git, .claude, .vscode prompt even with --dangerously-skip-permissions. Intentional but undocumented. (#35646)

Fix: Anthropic confirmed a fix is incoming.

Trap 5: /model Doesn't Update /status Immediately

/model changes the model for future API calls, but /status shows the old one. (#36835)

Fix: Send a new message after /model, or set via environment:

export ANTHROPIC_MODEL=claude-opus-4-6
Enter fullscreen mode Exit fullscreen mode

Trap 6: Claude Adds Flags Your Pattern Doesn't Expect

You allow Bash(git status:*). Claude runs git -C /path status. The -C flag breaks your pattern. (#36900)

Fix: Match the optional flag in a hook:

if echo "$COMMAND" | grep -qE '^\s*git\s+(-C\s+\S+\s+)?(status|log|diff|branch|show)'; then
    # auto-approve
fi
Enter fullscreen mode Exit fullscreen mode

Your hook returns permissionDecision: "deny" with exit code 2. For Bash commands, the tool is blocked. For Edit/Write — the file is modified anyway. (#37210)
Fix: Defense-in-depth — make the file read-only before the deny:

if [[ "$TOOL" == "Edit" || "$TOOL" == "Write" ]]; then
    if should_deny "$FILE"; then
        chmod 444 "$FILE" 2>/dev/null
        echo "BLOCKED: Edit denied by policy" >&2
        exit 2
    fi
fi
Enter fullscreen mode Exit fullscreen mode

The Pattern

6 out of 7 traps have the same fix: PreToolUse hooks. The permission system has edge cases. Hooks operate independently and don't have them.

npx cc-safe-setup
Enter fullscreen mode Exit fullscreen mode

667 hooks (at the time of writing). 10 seconds to install. Covers destructive commands, force push, .env leaks, syntax errors, and context monitoring.

GitHub


Every trap in this list came from a real GitHub Issue that my AI responded to. If you've hit a permission problem not listed here, drop a comment — I'll add it.


More on Claude Code hooks and safety patterns: How hooks work under the hood

Top comments (1)

Collapse
 
peacebinflow profile image
PEACEBINFLOW

This is an incredible breakdown of where "Declarative Intent" meets "Runtime Reality." It’s a classic systems problem: we define a policy that looks perfect on paper, but the execution layer (the Claude Code matcher) has its own quirks, regex edge cases, and OS-specific behavior that turn that policy into a sieve.

The "Permission Leak" Pattern
Your discovery in Trap 1—where allow effectively nukes ask—is a perfect example of logic shadowing. In many systems, we expect filters to be additive or restrictive, but here the "Allow" signal is acting like a global override. It’s a reminder that in autonomous systems, an "Allow All" is rarely just a convenience; it’s a total suspension of the system's "Self-Preservation" logic.

Hooks as the "Nervous System"
I love that your universal fix is the PreToolUse hook. If the built-in permission system is the "Static Firewall," the hooks are the "Deep Packet Inspection."

Hooks operate on the raw data stream (the tool input) before it hits the OS.

By shifting the logic from a configuration file (settings.json) to a script, you're moving from a Passive Policy to an Active Defense.

The "Defense-in-depth" fix for Trap 6—making the file read-only—is a brilliant bit of mechanical sympathy. It recognizes that if the software "deny" signal is flaky, you fall back to the OS-level immutable state.

The Flag Inflation Problem
Trap 5 (git -C status) is such a subtle, "human" error. We write patterns based on how we use a tool, but an AI agent uses the CLI like a surgical instrument, adding flags for path context or formatting that we never type manually. It’s a mismatch between Human Syntax and Machine-Native Commands. Your regex fix with the optional flag group is the necessary "translation layer" between those two worlds.

A Reflective Thought
I wonder if we should start viewing Claude Code permissions as a State Machine rather than a list? If the "State" is .claude/, then no tool—regardless of the command—should have "Write" access unless a specific "Unlock" event occurs.

Answering 57 issues in a week is a massive contribution to the ecosystem. You're basically mapping the "unknown unknowns" of autonomous developer tools in real-time.