Bash(command:*) allow rules do not prevent permission prompts for file-modifying commands

Status Fixed / completed
Maintainer reply None cached
Activity 7 comments · opened Jan 23, 2026 · closed May 4, 2026

Description

Bash commands explicitly listed in the allow array of .claude/settings.json do not prevent permission prompts - commands still prompt for permission despite being explicitly allowed.

Environment

  • Platform: Linux (Synology NAS)
  • OS Version: Linux 6.12.30+
  • Claude Code Version: Latest (January 2026)

Configuration

Project-level .claude/settings.json with 200+ explicit allow rules:

{
  "permissions": {
    "allow": [
      "Bash(mkdir:*)",
      "Bash(touch:*)",
      "Bash(mv:*)",
      "Bash(cp:*)",
      "Bash(curl:*)",
      "Bash(tar:*)",
      "Bash(echo:*)",
      "Bash(tee:*)",
      "Bash(sed:*)",
      "Bash(ln:*)",
      "Bash(chmod:*)"
      // ... 200+ other rules
    ],
    "ask": ["Bash(rm:*)"],
    "deny": ["Bash(rm -rf:*)", "Bash(sudo:*)", "Bash(wget:*)"]
  }
}

Steps to Reproduce

  1. Create .claude/settings.json with commands in allow array (full config available)
  2. Restart Claude Code session
  3. Run: mkdir test-dir
  4. Run: touch test-dir/file.txt
  5. Run: curl -sL https://example.com -o /tmp/test.tar.gz
  6. Run: tar -xzf /tmp/test.tar.gz

Test Results (2026-01-23)

Commands that PROMPTED despite being in allow list:

| Command | In Allow List | Result |
|---------|---------------|--------|
| mkdir perm-test | Bash(mkdir:*) | PROMPTED |
| touch test1.txt | Bash(touch:*) | PROMPTED |
| echo "test" > file.txt | Bash(echo:*) | PROMPTED |
| tee file.txt <<< "test" | Bash(tee:*) | PROMPTED |
| cp file1 file2 | Bash(cp:*) | PROMPTED |
| mv file1 file2 | Bash(mv:*) | PROMPTED |
| curl -sL url -o file | Bash(curl:*) | PROMPTED |
| tar -xzf archive.tar.gz | Bash(tar:*) | PROMPTED |

Commands that worked WITHOUT prompting:

| Category | Commands |
|----------|----------|
| Read-only system | ls, pwd, whoami, hostname, date, uname, df, ps, env |
| Read-only file | cat, head, tail, wc, grep, find, file, stat, md5sum |
| Version/help | git --version, node --version, curl --version, tar --version |
| Git operations | git status, git log, git branch, git diff, git remote |

Deny rules that worked correctly:

| Command | Result |
|---------|--------|
| rm -r dir | BLOCKED ✓ |
| rm -rf dir | BLOCKED ✓ |
| sudo ls | BLOCKED ✓ |
| wget url | BLOCKED ✓ |

Key Observations

  1. Allow rules don't work for file-modifying commands: mkdir, touch, cp, mv, echo redirect, tee, sed -i all prompt
  2. Allow rules don't work for network commands: curl with -o flag prompts
  3. Allow rules don't work for archive commands: tar extraction prompts
  4. Deny rules work correctly: Blocked commands are consistently blocked
  5. Read-only commands work: Never prompt (may not even check allow rules)

Conditions Verified

  • [x] Correct syntax Bash(command:*) per documentation
  • [x] Session restarted after config changes
  • [x] No settings.local.json overwriting permissions
  • [x] Valid JSON confirmed with jq .
  • [x] File in correct location (.claude/settings.json in project root)
  • [x] Commands NOT in deny or ask arrays

Hypothesis

It appears that:

  • Deny rules are checked and enforced
  • Read-only commands may bypass permission checks entirely
  • Allow rules for file-modifying/network commands are either not checked or not matched correctly

Related Issues

  • #17017 - Project-level permissions replace global instead of merging
  • #6900 - settings.local.json overwrites existing manual settings
  • #13340 - Global allow rules not recognized

Expected Behavior

Commands listed in the allow array with Bash(command:*) syntax should execute without prompting for permission.

Actual Behavior

File-modifying and network commands prompt for permission regardless of allow rules. Only deny rules and read-only commands behave as expected.

View original on GitHub ↗

7 Comments

github-actions[bot] · 7 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/18846
  2. https://github.com/anthropics/claude-code/issues/17321
  3. https://github.com/anthropics/claude-code/issues/20088

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

mrchris-ai · 7 months ago

Additional clarification: This issue affects both project-level (.claude/settings.json) AND global-level (~/.claude/settings.json) configurations.

During testing, we verified:

  • Global ~/.claude/settings.json with the same allow rules - same behavior (prompts for file-modifying commands)
  • Project-level .claude/settings.json - same behavior
  • Both configurations simultaneously - same behavior

The allow rules are not honored at either configuration level for file-modifying and network commands.

adamavenir · 7 months ago

Hitting this same issue with mkdir being blocked in directories that Claude is already authorized in. Thank you for filing.

dustin-starfoundry · 6 months ago

Systematic permission testing confirms this bug — also documents the reverse: commands auto-approving WITHOUT allow rules.

Environment: Claude Code v2.1.34, VS Code Extension, Windows 10, defaultMode: "acceptEdits"

Setup: .claude/settings.local.json with explicit allow rules. Tested 50 commands in a single session, user manually flagged each prompt.

Commands that PROMPT despite being in the allow list

| Rule in settings.local.json | Command Tested | Result |
|------|---------|--------|
| Bash(cd *) | cd /tmp | Prompted |
| Bash(cp *) | cp --help | Prompted |
| Bash(cp *) | cp --version | Prompted |
| Bash(mkdir *) | mkdir -p /tmp/test | Prompted |

All four are "file-modifying" or "directory-changing" commands. The allow rules are correctly formatted (confirmed other rules with same syntax work fine).

Commands that AUTO-APPROVE despite NO allow rule anywhere

| Allow rule? | Command Tested | Result |
|-------------|---------|--------|
| None | rm --help | Auto-approved |
| None | rm --version | Auto-approved |
| None | python --version | Auto-approved |

These commands are not in settings.local.json, ~/.claude/settings.json, or ~/.claude.json project allowedTools. They appear to be auto-approved by an internal classification system.

Control group — rules that DO work correctly

| Rule | Command | Result |
|------|---------|--------|
| Bash(ls *) | ls -la ... | Auto-approved |
| Bash(git commit *) | git commit -m "msg" | Auto-approved |
| Bash(git push *) | git push origin branch | Auto-approved |
| Bash(pnpm *) | pnpm build | Auto-approved |
| Not in allow list | curl --version | Prompted |
| Not in allow list | gh issue list | Prompted |

Summary

The permission system appears to have two separate issues:

  1. Allow rules are silently ignored for commands internally classified as "file-modifying" (cd, cp, mkdir)
  2. Commands auto-approve without any allow rule when internally classified as "read-only" (rm --help, python --version)

The user-facing settings give the impression of full control, but the internal classification overrides them in both directions.

yurukusa · 5 months ago

One common cause of this: Claude adds # comment lines before the command, which changes the string the permission matcher sees. A PreToolUse hook can strip those comments so the matcher works:

npx cc-safe-setup

Includes a comment-strip hook that removes leading # lines from bash commands before permission matching. Won't fix all cases (e.g., $(...) substitution also breaks matching — see #31373), but handles the comment case.

Source: comment-strip.sh

ronapelbaum2 · 3 months ago

Still reproducing on Claude Code desktop app Claude 1.7196.0 (2dbd78) (macOS).

Repro

A bare, single git add <file> command — no chaining, no redirects, no variables, no substitution — prompts for approval despite multiple overlapping allowlist patterns.

Settings (~/.claude/settings.json)

{
  "permissions": {
    "allow": [
      "Bash(git:*)",
      "Bash(git *)",
      "Bash(git add:*)",
      "Bash(git add)"
    ]
  }
}

Command that prompts

git add src/app/shopper-search/quick-search-modal/quick-search-modal.component.spec.ts

Observed

Permission prompt appears with only "Deny" and "Allow once" — no "Always allow" option (related: #36514).

[attach screenshot here]

Expected

Command matches at least four allowlist patterns and should execute without prompting.

What I've ruled out

  • No shell variables, substitution, or heredocs in the command
  • No chained operators (&&, ;, |, redirects)
  • No project-level settings.json overriding the user-global allowlist
  • No deny or ask rules anywhere
  • Verified with /permissions that the rules above are loaded
  • Restarted the session after every config change

Related open issues suggesting the underlying matching logic still has gaps

  • #20085 — compound commands of individually-allowed segments still prompt
  • #47394 — Bash(*) wildcard doesn't match all Bash commands
  • #58568 — read-only commands prompt for paths outside project even when Read is globally allowed
  • #36514 — no "Always allow" option for Bash mutations (so users can't click their way out)

Escape hatches that don't work

  • defaultMode: bypassPermissions in settings.json — desktop app ignores it (#42975, #38148, #29026)
  • --dangerously-skip-permissions — CLI flag, not exposed by desktop app
  • "Always allow" button — not offered for git add (#36514)

So the user-facing impact is: every commit costs two clicks in the desktop app (git add, then git commit), and there's no config or UI workaround. Considering reopening this or filing a new issue — happy to do whichever the maintainers prefer.

github-actions[bot] · 1 month ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.