Permission precedence: a broad allow in settings.local.json overrides ask rules, bypassing confirmation (contradicts documented deny→ask→allow order)

Status Fixed / completed
Maintainer reply None cached
Activity 1 comment · opened Jul 22, 2026 · closed Jul 22, 2026

Summary

A broad glob allow rule silently overrides a more-specific ask rule that matches the same command, so the confirmation dialog never appears. This directly contradicts the documented permission precedence, which states rules are evaluated denyaskallow (specificity-independent) and explicitly calls out this exact ask-vs-allow case.

Environment

  • Claude Code v2.1.205 (observed; current latest is v2.1.206, same release line)
  • macOS (Darwin)
  • Interactive session (default permission mode)

Expected behavior

The docs (Configure permissions) are explicit on this. Under Manage permissions:

Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change the order.
[...] The same precedence applies between ask and allow: a matching ask rule prompts even when a more specific allow rule also matches the same call.

And under Settings precedence, rule type — not which file the rule lives in — is what governs across scopes:

[...] deny rules from any scope are evaluated before allow rules.

So a command matching an ask rule must prompt even when a broader allow rule from another scope (e.g. settings.local.json) also matches — ask is evaluated before allow, regardless of specificity or scope.

Actual behavior

When an ask rule and a broader allow rule both match a command, the allow wins and the command runs with no confirmation dialog. The ask gate is effectively dead.

Minimal reproduction

In an empty directory:

mkdir -p /tmp/cc-perm-repro/.claude && cd /tmp/cc-perm-repro
echo '{ "permissions": { "ask":   ["Bash(gh pr merge *)"] } }' > .claude/settings.json
echo '{ "permissions": { "allow": ["Bash(gh pr *)"] } }'      > .claude/settings.local.json

Start an interactive session in that directory and run a command matching the ask rule, e.g. gh pr merge --help.

Expected: a confirmation prompt (matches ask: Bash(gh pr merge *)).
Actual: the command executes immediately, no prompt — the broader allow: Bash(gh pr *) from settings.local.json wins.

Note: here the ask rule is more specific than the allow rule, so both "rule specificity doesn't change the order" and the explicit ask-vs-allow sentence require a prompt. (Do not click "don't ask again" during testing — it would mask the result.)

Impact

Confirmation gates meant to protect irreversible / outward-facing actions (git push, git reset --hard, gh pr merge, publish, etc.) are silently defeated whenever any broader allow glob overlaps them — common when a local allowlist is grown to reduce prompt fatigue. The only reliable workaround today is ensuring no allow rule overlaps any ask rule across all scopes, which is fragile and hard to audit by hand.

Likely cause (hypothesis)

The behavior looks like ask-vs-allow is being resolved by settings-file precedence (settings.local.json outranks settings.json) instead of by rule-type precedence (ask before allow across all merged scopes). The "Settings precedence" section says rule type wins across scopes for deny vs allow; the same should hold for ask vs allow.

Question / requested fix

Should ask take precedence over a broader overlapping allow (as the docs state)? If the current behavior is intended, the precedence/scope-merging docs should be updated to describe the specificity/scope interaction that actually governs ask vs allow.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗