Permission wildcard warning is not deny-aware, has no suppression, and cannot be followed for variable slots
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
2.1.246 added a startup warning for permission allow rules with a wildcard before the subcommand. On a hardened enterprise config it fires 18 times on every launch, and all 18 are false positives. Three things make it impossible to act on.
1. The advice cannot be followed when the slot is inherently variable.
The warning says to "replace that * with the exact value you mean, or only use * after the subcommand". Neither is possible for:
Bash(git -C * status *)
The wildcard is a directory path, and git's own grammar puts the subcommand after it. The same holds for any CLI where a required global flag precedes the subcommand:
Bash(mycli --account=* logs tail)
Enumerating the values is possible but means every new account edits every rule, and a missed line fails silently: the rule stops matching and the user starts getting prompts with nothing explaining why.
2. The check is not deny-aware.
The warning names a specific vector — "options such as -c and --exec-path can run arbitrary commands". Our settings deny exactly those, and the deny is evaluated first:
"permissions": {
"allow": ["Bash(git -C * status *)"],
"deny": ["Bash(git -c *)", "Bash(git -C * -c *)", "Bash(git *--exec-path*)"]
}
A rule whose named vector is denied elsewhere in the same settings seems like the clearest case for staying quiet.
3. There is no way to acknowledge or suppress it.
sandbox.ignoreViolations exists for the analogous case of expected, benign sandbox denials, but there is no equivalent for permission-rule warnings. Eighteen lines before every session trains people to skim startup output, which is exactly where a warning that does matter will appear.
Separately, the trigger looks inconsistent. It appears to fire only when a bare * is followed by a fully literal token. In the same settings file:
Bash(aws * describe-*) -> silent
Bash(aws * logs tail) -> warns
Both have the identical wildcard in the identical position and both match options inserted there, so both carry the risk described. If that asymmetry is deliberate, documenting it would help; if not, the first form is under-reported.
What Should Happen?
Any one of these resolves it, in order of preference:
- Skip the warning when the same settings already deny the vector it names.
- Provide a suppression or acknowledgement mechanism, in the spirit of
sandbox.ignoreViolations. - Document that the pattern is unavoidable for variable slots, and reconsider the asymmetry above so the warning is at least consistent.
Error Messages/Logs
Permission allow rule (settings.json): Bash(git -C * status *) has a wildcard before the rest of the command, so it also matches any options inserted at that position and approves them without a prompt. For git, options such as -c and --exec-path can run arbitrary commands. Replace that * with the exact value you mean, or only use * after the subcommand (for example Bash(git status *)).
Permission allow rule (settings.json): Bash(aws * logs tail) has a wildcard before the rest of the command, so it also matches any options inserted at that position and approves them without a prompt. Replace that * with the exact value you mean, or only use * after the subcommand.
(16 more of the same shape on every launch.)
Steps to Reproduce
- In a settings file, add an allow rule whose wildcard precedes the subcommand, plus a deny rule covering the vector the warning names:
"permissions": {
"allow": ["Bash(git -C * status *)"],
"deny": ["Bash(git -c *)", "Bash(git -C * -c *)", "Bash(git *--exec-path*)"]
}
- Start Claude Code. The warning for the allow rule prints, despite the deny.
- Confirm the deny is effective:
git -C . -c core.pager=cat diff --statis refused. The warning still prints on the next launch. - Add
"Bash(aws * describe-*)"to allow and restart: no warning, though the wildcard sits in the same position as the rule in step 1.
Is this a regression?
Yes, this worked in a previous version — last working version 2.1.245.
To be precise: the warning is new and intentional in 2.1.246, so this is not a regression of the permission system itself. It is filed as one because the startup output was actionable before 2.1.246 and is not now.
Environment
- Claude Code version: 2.1.251
- Platform: Anthropic API
- Operating system: macOS host, rules also loaded in a Linux container
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗