Bash(command:*) allow rules do not prevent permission prompts for file-modifying commands
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
- Create
.claude/settings.jsonwith commands in allow array (full config available) - Restart Claude Code session
- Run:
mkdir test-dir - Run:
touch test-dir/file.txt - Run:
curl -sL https://example.com -o /tmp/test.tar.gz - 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
- Allow rules don't work for file-modifying commands: mkdir, touch, cp, mv, echo redirect, tee, sed -i all prompt
- Allow rules don't work for network commands: curl with -o flag prompts
- Allow rules don't work for archive commands: tar extraction prompts
- Deny rules work correctly: Blocked commands are consistently blocked
- 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.jsonoverwriting permissions - [x] Valid JSON confirmed with
jq . - [x] File in correct location (
.claude/settings.jsonin 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.
This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗