DEV Community

Cover image for This Claude Code Bug Has 17 Upvotes and 18 Comments. Here's the 30-Second Fix.
Yurukusa
Yurukusa

Posted on

This Claude Code Bug Has 17 Upvotes and 18 Comments. Here's the 30-Second Fix.

17 people upvoted this bug and it has 18 comments. The ask permission list gets completely ignored when Bash is in the allow list.

You want: "auto-approve safe commands, confirm dangerous ones."
You get: everything auto-approved, no confirmation ever.

The Problem

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

Expected: rm -rf / triggers a confirmation.
Actual: rm -rf / runs immediately. ask is silently ignored.

This has been open since August 2025. 17 upvotes, 18 comments. No fix.

The Workaround: PreToolUse Hooks

Hooks operate independently of the permission system. A PreToolUse hook runs after permissions are resolved but before the tool executes. Exit code 2 = hard block.

{
  "permissions": {
    "allow": ["Bash(*)"]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "~/.claude/hooks/destructive-guard.sh" }]
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

The hook reads the command from stdin JSON and blocks dangerous patterns:

#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# Block rm on sensitive paths
if echo "$COMMAND" | grep -qE 'rm\s+(-[rf]+\s+)*(\/|~|\.\./)'; then
    echo "BLOCKED: rm on sensitive path" >&2
    exit 2
fi

# Block git reset --hard
if echo "$COMMAND" | grep -qE '^\s*git\s+reset\s+--hard'; then
    echo "BLOCKED: git reset --hard" >&2
    exit 2
fi

# Block force push
if echo "$COMMAND" | grep -qE 'git\s+push\s+.*(-f\b|--force\b)'; then
    echo "BLOCKED: force push" >&2
    exit 2
fi

# Block git add .env
if echo "$COMMAND" | grep -qiE 'git\s+add\s+.*\.env'; then
    echo "BLOCKED: git add .env" >&2
    exit 2
fi

exit 0
Enter fullscreen mode Exit fullscreen mode

Why This Is Better Than ask

The permission system has other issues too. Trailing wildcards in compound patterns like Bash(ssh * uptime *) don't match when the command has no arguments — ssh host uptime fails but ssh host uptime -s passes (#36873). Hooks use proper regex and don't have this problem.

  1. Hooks can't be overridden by other permissions. allow doesn't cancel them.
  2. They can inspect the full command. Not just pattern matching on the tool name.
  3. They can check system state. Mount points, file existence, git branch.
  4. Exit code 2 is a hard block. Claude can't override it.

One Command Setup

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

Installs 8 production-tested hooks covering destructive commands, force push, .env leaks, syntax errors, and context window monitoring. 116 automated tests. GitHub


This pattern — allow for speed, hooks for safety — is what ask should have been. Until the permission system is fixed, hooks are the way.

Full autonomous setup: Claude Code Ops Kit — 16 hooks + 5 templates + 3 tools.

🛠 Free: claude-code-hooks — 16 production hooks, open source.

Top comments (0)