[BUG] permissions from user settings.json is NOT applied at project level
Environment
- Platform (select one):
- Other: Claude Code on macOS with VS Code
- Claude CLI version: 1.0.68 (Claude Code)
- Operating System: macOS Darwin 23.6.0
- Terminal: Terminal App
Bug Description
User-level permissions in ~/.claude/settings.json are not being enforced
during command execution, even though they appear as loaded in the
/permissions command. The same permissions work correctly when placed in
project-level .settings.local.json but fail when moved to user-level
settings.
Steps to Reproduce
- Copy working permissions from a project's .settings.local.json to
user-level ~/.claude/settings.json:
{
"permissions": {
"allow": [
"mix:*",
"mcp__serena__*",
"mcp__context7__*",
"Bash(ls:*)",
"Bash(find:*)",
"Bash(grep:*)",
"Bash(sqlite3:*)",
"Bash(mkdir:*)",
"Bash(cp:*)",
"Bash(mv:*)",
"Bash(git add:*)",
"Bash(git push:*)",
"Bash(git checkout:*)",
"Bash(git stash show:*)",
"Bash(git stash pop:*)",
"Bash(git fetch:*)",
"Bash(git stash push:*)",
"Bash(git merge:*)",
"Bash(git cherry-pick:*)",
"Bash(python:*)",
"Bash(python3 -m pip install:*)",
"Bash(npm install:*)",
"Bash(npx playwright test:*)"
]
}
}
- Open a project in VS Code with Claude Code
- Run /permissions - it correctly shows all permissions as loaded
- Try to run any allowed command (e.g., mix --version)
- Claude Code still asks for permission despite the command being in the
allow list
Expected Behavior
- I want a way to allow the mcp of serena to execute all its commands without asking for explicit permission each time.
- Commands in the user-level allow list should execute without requiring
approval
- User-level permissions should work identically to project-level
permissions
- If /permissions shows a command as allowed, it should not require
approval
Actual Behavior
- All commands require manual approval even when listed in user-level
permissions
- /permissions command shows the permissions as loaded but they are not
enforced
- The exact same permissions work when placed in project
.settings.local.json but not in ~/.claude/settings.json
- MCP wildcard permissions (e.g., mcp__serena__*) also don't work at the
user level
Additional Context
- These permissions were originally auto-generated by Claude Code (not
manually written) - I just copied them from .settings.local.json to the user-level settings.json
- This significantly impacts workflow as every command requires manual
approval across all projects
23 Comments
Found 3 possible duplicate issues:
If your issue is a duplicate, please close it and 👍 the existing issue instead.
🤖 Generated with Claude Code
This permissions issue may be related to #5314 - PostToolUse hooks not triggering for Edit operations on .cs files.
The problem in #5314 involves hooks configured in
.claude/settings.jsonnot being executed despite proper syntax and verbose mode being enabled. If permissions from user settings.json are not being applied at the project level as described in this issue, it could explain why PostToolUse hooks fail to execute.Our hook configuration includes:
If the settings.json configuration isn't being properly applied at the project level, the hook system might not be receiving the configuration needed to execute hooks after Edit/MultiEdit/Write operations.
I'm having the same issue! in MacOS, using claude code, user/.claude/settings.json allow list and deny list commands are completely ignored. It is a bit annoying to deal with this.
Same here on MacOS. Would love a real fix.
Same problem on my end. I am trying to run grunt commands from Claude and it keeps asking for permission even though I ask CC to add it to the allow list.
Same issue, and its extra annoying with plan mode as it does not respect the bypass permissions that I set when launching the cli. The global bypass permissions should be a setting, not a mode. So I tried to workaround by adding permissions and it doesn't use them.
@tiagoefreitas Not sure if this will apply to your situation, but you may want to check
/statuswhen in Claude code to see if there were issues loading the settings file. I discovered that it does not proactively report issues with settings files, so it will silently ignore those with typos for example. But if you run/status, then you'll see a message if there was an issue with one of your settings (it was my .claude/settings.json in my case). Then it took a little trial and error to understand where there was a typo because the message did not give details, but I was able to sort it out. I hope this helps.According to your advise, I fixed my problem.
``` bash
check whether settings.json is invalid
/status
claude provide where is invalid
/doctor
Detailed Investigation Report: Permissions Ignored Despite Explicit Configuration
### Environment
.claude/settings.local.json### Problem Statement
Claude Code repeatedly requests permissions for actions explicitly allowed in
.claude/settings.local.json, including:uv run ruff check,uv run ruff format,uv run python -m py_compilemcp__basic-memory__edit_note,mcp__basic-memory__write_note, etc.All of these permissions were explicitly listed in the
permissions.allowarray.### Investigation Steps
#### Theory 1: Path Format Issue (Single vs Double Slash)
Based on issue #6850 and #6881, we hypothesized that absolute paths needed double slashes (
//) on macOS.Changes Made:
```
// Before
"Read(/Users/arnon/projects/**)"
"Bash(/Users/arnon/bin/send_text:*)"
// After
"Read(//Users/arnon/projects/**)"
"Bash(//Users/arnon/bin/send_text:*)"
Result: ❌ Failed - Still requested permissions
Test Method: Fresh Claude instance, asked to run uv run ruff check on a file
Outcome: Permission prompt appeared despite pattern being in allow list
Theory 2: Wildcard Syntax Issue (Colon vs Space)
Based on issue #819, we hypothesized that command:* syntax doesn't match space-separated arguments.
Changes Made:
// Before
"Bash(uv run ruff check:*)"
"Bash(uv run ruff format:*)"
// After
"Bash(uv run ruff *)"
Result: ❌ Failed - Still requested permissions
Test Method: New Claude instance after configuration change
Outcome: Still prompted for permission to run uv run ruff check bin/checked_bash.py
Theory 3: Configuration File Corruption
Rolled back .claude/settings.local.json to a known-good version from Oct 27 (commit a079a14) using git.
Result: ❌ Failed - Still requested permissions with old configuration
Test Method: Fresh Claude instance with rolled-back configuration
Outcome: Permissions still requested, ruling out configuration file as the cause
Evidence of Core Bug
Verification Steps Taken
# Verified settings file exists and contains permissions
$ grep -n "edit_note" .claude/settings.local.json
39: "mcp__basic-memory__edit_note",
# Verified only one settings file in project
$ ls -la .claude/settings*.json
-rw-r--r--@ 1 arnon staff 2845 Nov 6 12:09 .claude/settings.local.json
# Tested with git history
$ git log --oneline -- .claude/settings.local.json
ffe4d62 FLO-72: Add customers table page with sortable columns
99fa209 FLO-72: Implement users table page infrastructure
a079a14 FLO-72: prep for implementing table pages
# Rolled back and tested
$ git checkout a079a14 -- .claude/settings.local.json
# Result: Still prompted for permissions
Screenshot Evidence
Permission prompt appeared for uv run ruff check bin/checked_bash.py despite:
Conclusion
The permission system in Claude Code 2.0.34 does not read or respect .claude/settings.local.json at all, or the pattern matching is completely broken for all pattern types.
This is not caused by:
This appears to be a fundamental bug in the permission system initialization or matching logic affecting:
The system prompts for permissions on every fresh instance regardless of configuration, making the settings file effectively non-functional.
Reproducibility
100% reproducible on every fresh Claude Code instance with any configuration pattern tested.
```
This critical security bug has been open for 3 months with no assignee. Permission system is completely non-functional in v2.0.34. Escalating to
security@anthropic.com and support@anthropic.com
This was useful in finding the issues I had in ~/.claude/settings.js Thanks @tiagoefreitas
Agree with @arnonmoscona. This bug and its several companions pose a privacy and security risk. Colleagues are advocating the use of
--dangerously-skip-permissionsbecause the permission system is so broken. Understandably so, because being prompted for every little detail gets very annoying very fast.If my
~/.claude/settings.jsoncontains entries indeny, those restrictions had better be respected. If there's a parsing error (as JSON is wont to provoke with its comma requirements), claude MUST abort startup and report such. Rather than the current dangerous behaviour of simply ignoring the settings files and all its denies altogether. This is especially important for the User settings file, which is outside project directories and thus more likely to be edited outside an IDE with live syntax error feedback.After fixing syntax error and restarting,
/permissionslists the expected allows and denies. But claude keeps asking whether it should apply the most trivial of edits. Given that, I'm not particularly trusting that denies are respected either.I ran into this as well, and surprisingly this lead to sandboxing being entirely disabled. It strikes me that sandboxing should be controlled in an entirely separate, simple file so the chances of malformed configuration can never lead to it being disabled.
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
This still keeps coming back up. We really could use some attention from the team to fix permissions @bcherny
between this and claude not reading the user .mcp.json, cc is getting frustrating to use
None of these following
settings.jsonworks:With double slashes (at the beginning):
With a single slash (at the beginning):
At
/private/tmp/test-workspaces/.claude/settings.jsonand/private/tmp/test-workspaces/.claude/settings.local.jsonAt
~/.claude/settings.jsonand~/.claude/settings.local.json:claudewas being started at/private/tmp/test-workspaces/But it always ask for permissions when writing to
/private/tmp/test-workspaces/permission-test.txt(although it was pre-approved)<img width="593" height="381" alt="Image" src="https://github.com/user-attachments/assets/ae0929f4-5fed-45f9-beb7-3a71f778dffa" />
I don't want to run
claudewith--dangerously-skip-permissionsflag. But runningclaudewithout it is quite frustrating now...Wondering how is it working at Anthropic? @bcherny
denyis also not working:/private/tmp/clawk-workspaces/1/.claude/settings.json:Start
claudeorclaude --dangerously-skip-permissions:<img width="1093" height="1030" alt="Image" src="https://github.com/user-attachments/assets/3673daa7-e98d-48d4-ad51-091563b1adc9" />
claudestill write outpermission-test.txtSolution Found: Path Format Issue
After extensive testing, I found that user-level permissions DO work - the issue is the path format.
Root Cause
Single-slash paths like
/Users/james/**are interpreted as relative paths from the settings file location, not absolute paths.The Fix
Use double-slash
//for absolute paths:Verification
~/.claude/settings.jsonwith//paths-r)This is documented in #6881 but easy to miss. The single-slash format that Claude Code itself generates when you accept prompts may be contributing to the confusion.
Additional Note
Path-restricted Bash commands like
Bash(rm:/tmp/**)also don't work reliably. Use wildcardsBash(rm:*)with deny rules instead.Got tired of waiting for fixes. Created https://github.com/arnonmoscona/toolguard as an enhanced drop-in replacement to the native permissions system using hooks. As far as I can tell it is syntax-compatible, but it has more features and allows also new matching patterns. The simplest setup is just to setup the hook as documented, but you can go far beyond if you want. I will add a new feature soon to overcome some of the annoying behaviors I find around permissions.
I'd welcome any feedback, comments, PRs. This is new, to treat it carefully. "works on my machine" is not really good enough, but I am one guy with one machine. So there's that...
Workaround — hooks in user settings.json are enforced regardless of project settings:
While permission rules may not cascade correctly from user to project level, hooks defined in
~/.claude/settings.jsondo apply globally to all projects.Hooks bypass the permission system entirely — they run before tool execution and exit 2 to hard-block, regardless of what project-level settings say.
Quick install:
npx cc-safe-setup— writes hooks to~/.claude/hooks/and registers them in user-level~/.claude/settings.json. Works across all projects.User-level permissions in
~/.claude/settings.jsondon't reliably apply at project level — this is a known issue. Hooks are the fix because they always propagate:Hooks defined in
~/.claude/settings.jsonfire in every project. Unlike permission patterns, hook execution doesn't have the user/project level scoping bug. This is the reliable way to enforce user-level permissions across all projects.FYI toolguard is now at 0.3.0 - while takeover mode is nominally in alpha state, it's been working perfectly for me for a while. So this issue does not really affect me any more and I have a much more flexible permissions configuration.
https://github.com/arnonmoscona/toolguard](https://github.com/arnonmoscona/toolguard%5D(https://github.com/arnonmoscona/toolguard))