Deny rules for Read tool not enforced when broad allow rule exists
Description
Deny rules in permissions.deny for the Read tool are not being enforced when a broad Read(**) allow rule exists in permissions.allow.
Steps to Reproduce
- Add the following to
~/.claude/settings.json:
{
"permissions": {
"allow": [
"Read(**)"
],
"deny": [
"Read(**/.secrets*)"
]
}
}
- Create a file
~/.secretswith some content - Start a new Claude Code session
- Ask Claude to read
~/.secrets
Expected Behavior
The Read tool should be blocked with a permission denied error, since **/.secrets* matches the path ~/.secrets (expands to /Users/<username>/.secrets).
Deny rules should take precedence over allow rules for matching paths.
Actual Behavior
The Read tool successfully reads the file contents. The deny rule is completely ignored.
Environment
- OS: macOS (Darwin 24.6.0)
- Claude Code version: Latest as of 2025-01-19
Additional Context
This is a security concern as users may believe sensitive files are protected by deny rules when they are not. The deny list included patterns for:
.envfiles.secretsfiles.pemand.keyfilescredentials/directories.aws/and.ssh/directories
None of these protections are effective if a broad Read(**) allow rule exists.
Suggested Fix
Deny rules should always be evaluated and take precedence over allow rules, regardless of specificity or order in the lists.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗