Skip to content

Permissions matching is fundamentally broken — 30+ open issues, no staff engagement, community building workarounds #30519

@kylesnowschwartz

Description

@kylesnowschwartz

Summary

The permission matching system doesn't work. It's been broken since mid-2025, there are 30+ open issues about it, and Anthropic staff have left one comment across all of them — a workaround suggestion in September 2025 that didn't fix anything.

The community is now writing custom PreToolUse hooks in Python to reimplement permission enforcement from scratch (#18846). That's where we are.

What's broken

I have 136 allow rules, 2 deny rules, and 31 ask rules in my settings.json. Carefully segmented by risk. I still get prompted constantly for commands that should match.

Wildcards don't match compound commands (#25441, #29616, #29529). Bash(git:*) doesn't match git add file && git commit -m "message". The * only works within a single simple command. Claude generates compound commands constantly, so the wildcards are useless in practice.

"Always Allow" saves dead rules (#6850, #11380). Click "Always Allow" on git commit -m "fix typo" and it saves that exact string — commit message and all. Never matches again. Over time settings.local.json fills up with hundreds of one-off rules while the actual wildcard patterns sit there unused.

User-level settings don't apply at project level (#5140, #18160). Rules in ~/.claude/settings.json show up in /permissions but don't match anything. Same rules in project-level settings.local.json reportedly work fine.

Quote-tracking bypasses the allow list entirely (#30345). Commands with quotes in # comments trigger a safety warning that ignores all allow rules. Filed on v2.1.63, which is current.

Deny rules have the same bugs (#25441 comments, #18613). Multiline commands bypass deny rules too. Flag reordering can also get around them. So the permission system isn't just annoying — it's not enforcing the safety constraints users configured.

Colon vs space syntax is contradictory (#30113). Bash(git:*) and Bash(git *) behave differently. The docs don't agree on which is correct. "Always Allow" generates one syntax, users configure the other.

The security problem

Users who care about permissions have three options right now:

  1. Click through every prompt without reading. Defeats the purpose.
  2. Switch to bypassPermissions. Disables everything including deny rules.
  3. Build custom hooks to reimplement matching.

Option 3 is what people are actually doing. Community-built Python scripts with no security review, no tests against adversarial inputs, no correctness guarantees. The first-party permission system exists so users don't have to do this.

Staff engagement

Issue Filed Problem Staff response
#5140 Aug 2025 User settings not applied at project level None
#6850 Aug 2025 Allow list not working, dead rules accumulating One workaround (didn't fix it)
#11380 Nov 2025 Prompts despite "Always Allow" None (oncall label)
#18160 Jan 2026 Allow permissions ignored None
#18846 Jan 2026 Permissions not enforced at all None
#25441 Feb 2026 Wildcards don't match multiline None
#29187 Feb 2026 "Always Allow" suggests wrong patterns None (labeled regression)
#29616 Feb 2026 Wildcard patterns don't match None
#30113 Mar 2026 Contradictory documentation None
#30345 Mar 2026 Quote-tracking bypasses allow list None

No milestones. No Anthropic-authored PRs. No roadmap. No tracking issue.

What we need

  1. A staff response. Even just "we know, it's on the roadmap for Q3" would change the dynamic. 30+ issues spanning 7 months with silence is not a good look for a security-relevant subsystem.

  2. Compound command matching. Bash(git:*) should match git add && git commit. Single-command-only matching doesn't reflect how Claude actually generates bash.

  3. Smarter "Always Allow." Approving git commit -m "fix typo" should save Bash(git commit:*), not the verbatim string.

  4. Scope enforcement that works. User-level rules should match everywhere they show up.

  5. Deny rules that hold. No variation of a denied command — multiline, reordered flags, embedded in a chain — should execute without prompting.

  6. One clear document covering syntax, matching semantics, scope hierarchy, and known limitations.

  7. A tracking issue so the community can follow progress instead of filing duplicates.

Environment

  • Claude Code v2.1.63
  • macOS Darwin 24.6.0
  • 136 allow, 2 deny, 31 ask rules in ~/.claude/settings.json
  • defaultMode: "acceptEdits"
  • Running a PermissionRequest hook as a workaround

Related issues

#5140, #6850, #11380, #18160, #18613, #18846, #25441, #27688, #29187, #29529, #29616, #30113, #30345

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions