Debugging a Permission Rule That Won't Take Effect
Your team's .claude/settings.json contains:
{
"permissions": {
"allow": ["Bash(aws s3 ls)"],
"deny": ["Bash(aws *)"]
}
}
An engineer reports that aws s3 ls still prompts for approval every
time, even though they explicitly allowed it.
- Explain exactly why the
allowrule has no effect here. - Rewrite the configuration so that
aws s3 lsruns without a prompt while every otherawssubcommand still requires approval. - A teammate suggests moving the
allowrule into.claude/settings.local.jsoninstead, reasoning that local settings have higher precedence than project settings. Would that fix it? Why or why not?
1. Why the allow rule has no effect:
Claude Code evaluates permission rules in a fixed order — deny, then
ask, then allow — and the first match in that order wins regardless
of how specific a lower-priority rule is. Bash(aws *) is a deny rule
that matches aws s3 ls (the wildcard covers any aws subcommand,
including this one). Because deny is checked first and it matches, the
call is blocked before Claude Code ever consults the allow list. A
broad deny rule cannot carry allowlist exceptions — there is no way for
a narrower allow to punch a hole in a broader deny.
2. Fix — narrow the deny rule instead of trying to except the allow:
{
"permissions": {
"allow": ["Bash(aws s3 ls)"],
"deny": ["Bash(aws s3 rm *)", "Bash(aws ec2 terminate-instances *)"]
}
}
The general fix is to invert the approach: rather than denying broadly
and trying to carve out an allow exception (which doesn't work), deny
only the specific dangerous subcommands and let everything else fall
through to the normal ask/allow flow. If the intent really is "block
all of aws except read-only listing," an equally valid approach is to
keep the broad deny and add a narrower deny is not what's needed here —
the fix is recognizing that allow can never override a matching deny,
so the deny rule itself must be made precise enough to not catch the
commands that should be allowed.
3. Would moving the allow rule to local settings help? No.
This is a common misconception. Precedence-by-scope governs most
settings (a higher-precedence scope's value replaces a lower one's),
but permissions rules are the explicit exception to that model: they
merge across every scope rather than override. A deny rule set in
project settings stays in effect no matter what a local or user-scope
file says — you cannot un-deny something from a lower-priority
perspective, and local settings are not "higher priority" for the
purposes of permission evaluation the way they would be for, say, the
model field. The engineer's assumption conflates the general settings
precedence model with the permissions-specific merge behavior. The only
way to allow aws s3 ls here is to change the deny rule so it no
longer matches that specific command.
Share this question