Thanks for building this — the "standing permission debt" angle is a real gap in the Claude Code tooling ecosystem, and the defensive engineering (loopback-only UI, symlink refusal, read-only ~/.claude.json) is impressive for a v0.1.0.
I ran audit --show-safe against a real, heavily-used config (183 allow rules across settings.json + settings.local.json, macOS) and found two systematic detection gaps where the most dangerous rules are the ones that pass as safe.
1. Bare wildcards are classified SAFE
from grantguard.core.detectors import apply_detectors
apply_detectors("Bash(*)") # -> SAFE
apply_detectors("Skill(*)") # -> SAFE
Bash(*) is the widest grant Claude Code supports — any shell command, forever. It should arguably be the single highest-severity finding in any audit, but it lands in the "Scoped / read-only / harmless" bucket. Meanwhile Bash(git *) is flagged OVERBROAD, which reads upside-down in the report: every scoped-but-broad rule gets flagged while the unscoped catch-all sails through.
2. Colon-syntax prefix wildcards (Bash(cmd:*)) are invisible to the detectors
apply_detectors("Bash(nc *)") # -> OVERBROAD
apply_detectors("Bash(nc:*)") # -> SAFE
apply_detectors("Bash(killall *)") # -> OVERBROAD
apply_detectors("Bash(killall:*)") # -> SAFE
apply_detectors("Bash(sudo cp:*)") # -> SAFE
apply_detectors("Bash(crontab:*)") # -> SAFE
Bash(cmd:*) and Bash(cmd *) are semantically equivalent prefix matchers in Claude Code's permission syntax — but only the space form is detected. This matters more than it looks: the colon form is what Claude Code itself writes when a user clicks "always allow", so rules accumulated organically through normal use are predominantly colon-syntax. In my run, all 42 colon-syntax command-family wildcards in settings.local.json passed as safe, including sudo-prefixed ones and persistence-capable commands like crontab.
Expected behavior
Bash(*) / Skill(*) / bare * variants flagged at the highest severity (arguably above OVERBROAD — there's no command family to reason about at all).
- Colon syntax normalized to the same representation as space syntax before detectors run, so
Bash(nc:*) and Bash(nc *) classify identically.
Happy to provide the full (redacted) audit output if useful. Tested on commit from 2026-07-08, Python 3.11, macOS.
Thanks for building this — the "standing permission debt" angle is a real gap in the Claude Code tooling ecosystem, and the defensive engineering (loopback-only UI, symlink refusal, read-only
~/.claude.json) is impressive for a v0.1.0.I ran
audit --show-safeagainst a real, heavily-used config (183 allow rules acrosssettings.json+settings.local.json, macOS) and found two systematic detection gaps where the most dangerous rules are the ones that pass as safe.1. Bare wildcards are classified SAFE
Bash(*)is the widest grant Claude Code supports — any shell command, forever. It should arguably be the single highest-severity finding in any audit, but it lands in the "Scoped / read-only / harmless" bucket. MeanwhileBash(git *)is flagged OVERBROAD, which reads upside-down in the report: every scoped-but-broad rule gets flagged while the unscoped catch-all sails through.2. Colon-syntax prefix wildcards (
Bash(cmd:*)) are invisible to the detectorsBash(cmd:*)andBash(cmd *)are semantically equivalent prefix matchers in Claude Code's permission syntax — but only the space form is detected. This matters more than it looks: the colon form is what Claude Code itself writes when a user clicks "always allow", so rules accumulated organically through normal use are predominantly colon-syntax. In my run, all 42 colon-syntax command-family wildcards insettings.local.jsonpassed as safe, includingsudo-prefixed ones and persistence-capable commands likecrontab.Expected behavior
Bash(*)/Skill(*)/ bare*variants flagged at the highest severity (arguably above OVERBROAD — there's no command family to reason about at all).Bash(nc:*)andBash(nc *)classify identically.Happy to provide the full (redacted) audit output if useful. Tested on commit from 2026-07-08, Python 3.11, macOS.