Bible Network Crypto DeFi Onchain RWA AI Agent Stablecoin Chain SAFU CryptoTax DeFAI AGI Claude Me Claude Skill Claude Design Claude Cowork
Independent Media
Not affiliated with any project
Exploring the Frontier of AI Intelligence
claude-me.com
LATEST
Claude Code Adds --restricted Mode: A Minimal-Authority Starting Point for Unfamiliar Projects  ·  Claude Code Fixes `/cd`: New Directory Settings Now Apply Immediately, No More Waiting for Resume  ·  Claude Code Adds a Startup Warning: `Bash(git * main)` Matches Far More Than You'd Expect  ·  Claude Code's --worktree Now Accepts a GitLab Merge Request URL Directly, No Number Conversion Needed  ·  Claude Code Remote Control Now Streams Live: Every Foreground Subagent Tool Call, Visible on Your Phone  ·  Claude Code Adds PreModelSwitch/PostModelSwitch Hooks: Switching Models Can Finally Be Intercepted and Logged
practice

Claude Code Adds a Startup Warning: `Bash(git * main)` Matches Far More Than You'd Expect

30-Second Version · For the impatient
`Bash(git * main)` looks like it has two constraints written in, but it's actually looser than a rule with just one — because the range that * matches includes the very subcommand you thought was being restricted.

Full Explanation +
01 · Why did this happen?

Why is putting * at the very start or end of a command usually fine, while putting it in the middle (before the subcommand) is especially error-prone?

The key is the subcommand's position. Take Bash(npm run ) as an example: the is at the end, and everything before it — npm run, which includes the subcommand — is written literally and fixed. So this rule is clearly scoped to "anything after npm run," and it won't accidentally allow a completely different subcommand like npm install. The same logic applies when is at the very beginning (like the official example Bash( --version)) — the fixed part sits at the other end, and the actual scope is comparatively easy to read at a glance.

What's genuinely error-prone is a pattern where the subcommand itself falls within the range the matches — like git * main, where the subcommand (whether it's log, merge, or push) sits sandwiched between two fixed pieces of text, and since can match any text, the subcommand is naturally within the range that can be substituted. This pattern visually "looks" constrained at both ends, which easily gives the impression that the middle is somewhat restricted too — but the middle is actually the wide-open part that determines exactly what the command does.

02 · What is the mechanism?

What actual security risk does this create in practice — is it more than just "the rule was written wrong"?

The real risk is that once the subcommand falls within the range * matches, it can end up allowing git operations you never intended to permit at all. Per the official documentation's example, Bash(git * main) allows git -c core.fsmonitor=<script> diff main — a command carrying a -c flag. The -c flag lets git run an external program you specify during execution, which is no longer just "the git scope was written too broadly." It means a rule you thought only covered something like git log ends up opening a doorway that can execute arbitrary external commands.

This is also why official documentation specifically calls out this warning on its own — compared to a simple "the rule is too loose and covers too many git subcommands," the additional risk of this pattern is that it allows variants carrying dangerous flags (like -c), and those variants still superficially look like "a git command related to the main branch," making them unlikely to stand out as anomalous during a rule review.

03 · How does it affect me?

If my project already has rules written this way, how do I actually check for and fix them?

Step one is watching for whether this warning appears when starting Claude Code after upgrading to 2.1.246 — the warning itself is the most direct check, no need to manually dig through settings files yourself looking for this pattern. If you have an older configuration on hand, you can also directly search settings.json for rules starting with Bash( that contain a * followed by non-wildcard text, paying particular attention to rules that look like they're "scoped to a specific branch" or "a variant scoped to a specific subcommand."

Step two is going back to confirm the original intent behind each rule you find. If the intent was "restrict to a specific subcommand, arguments unrestricted," the correct fix is moving the * to after the subcommand (turning git * main into git log * main, for example). If the intent was genuinely "allow these several git operations as long as the target is the main branch," you may need to reconsider whether this rule should exist at all, because leaving the subcommand unrestricted inherently means the allowed range is far broader than most people would intuitively assume.

Step three, after fixing it, is actually testing a few commands you'd expect to be allowed and a few you'd expect not to be, to confirm the corrected rule's behavior matches your original intent — not just checking that the syntax was changed correctly.

04 · What should I do?

Besides git, does this "* before the subcommand" problem also happen with other commonly used commands?

Yes. This problem is fundamentally unrelated to git itself — it's a matching trap that can occur with any command following a "program name + subcommand + arguments" structure. As long as a tool's behavior is determined by its subcommand (rather than plain flag arguments), putting * before the subcommand lets the subcommand itself fall within the range that can be substituted. Common examples include docker (where docker run and docker exec behave very differently), npm (where npm install and npm run mean completely different things), or any CLI tool with a subcommand structure that shows up in your own project.

A more reliable checking habit in practice is, every time you write a Bash allow rule, to ask yourself "which part of this command is the keyword that actually determines what it does" — and make sure that keyword (usually the subcommand) is written before the , fixed in place, rather than left within the range can match. This principle isn't specific to git — it's a general check applicable to any CLI tool with a subcommand structure.

Full Content +

Claude Code 2.1.246 (part of the August 2026 update sequence) added a startup warning that's easy to overlook but has a real impact on whether your permission rules actually mean what you think they mean: if a Bash allow rule has a wildcard (*) placed before the subcommand — like Bash(git * main) — a warning appears at startup, because this kind of pattern matches a far wider range than intuition suggests. This piece explains what the warning is flagging and how the matching logic actually works underneath it.

How Bash Rule Matching Works: Whole Command Text, With `*` Standing In for Any Text

Official documentation is direct about this: Bash rules match the whole command text, with * standing in for any text, including spaces. Claude Code treats whatever is written literally before the * as the fixed constraint on the rule — meaning where you place the * directly determines what the rule actually restricts.

Why `git * main` Matches Far More Than You'd Expect

Take the command git log --oneline main as an example: git is the program itself, and log is the subcommand — the subcommand, not the program name, is what actually determines what the program does. If you write Bash(git * main), the intent might be "allow various log-related arguments, as long as it ends with main." But Claude Code's actual matching logic treats git before the * as one constraint and main after it as another, with the * in between able to match any text, including the subcommand itself. The actual result: this rule allows git merge main, git push origin main, and even git -c core.fsmonitor=<script> diff main — a command carrying a -c flag that lets git run a program you name — because -c is also within the range * matches. Conversely, the plain command git log main (with nothing in between) is actually not matched by this rule.

The Correct Pattern: Put the `*` After the Subcommand

To achieve the original intent of "allow log-related commands only, with any arguments," the correct way to write it is putting the subcommand before the *: Bash(git log * main). This way, git plus log together become the fixed constraint, and * only matches arguments between log and main — so git log --oneline main and git log -5 main are correctly matched, while plain git log main (nothing in between) isn't matched by this rule, nor is a completely different subcommand like git push origin main.

The Real Problem This Warning Solves

The risk from this kind of rule isn't as obvious as "no restriction at all" — a rule with literally zero restriction is easy to spot at a glance. The real risk is that Bash(git * main) looks restricted on the surface (it does contain both git and main, after all), but its actual matching range is far broader than the literal text suggests, and that gap isn't easy to catch by eye during a rule review. What the 2.1.246 startup warning addresses is exactly this gap between a rule looking reasonable and actually being far looser than expected. If you've ever written an allow rule with a wildcard placed before a subcommand, it's worth checking after upgrading whether this warning appears at startup, and re-confirming that the rule's actual matching range matches what you originally intended.

Sources: Configure permissions - Claude Code Docs, Claude Code v2.1.246 Major Updates - DevelopersIO
Diagram
萬用字元位置決定固定範圍wildcard 放在子指令前(git * main)會讓子指令本身可被替換,匹配範圍遠比字面寬;放在子指令後(git log * main)才能正確限定範圍Where the * Goes Changes What's FixedBash(git * main)Fixed: git ... main* covers the subcommand tooMatches: merge main,push origin main, -c ... diff mainWider than it looksBash(git log * main)Fixed: git log ... mainsubcommand locked inMatches: --oneline main,-5 main (log only)Scoped as intendedClaude Me · claude-me.com
Feel free to share. Please credit the source.
Ask a Question
Please enter at least 10 characters
Related Terms
Related Articles
Claude Code Adds --restricted Mode: A Minimal-Authority Starting Point for Unfamiliar Projects
practice · Sep 04
Claude Code Fixes `/cd`: New Directory Settings Now Apply Immediately, No More Waiting for Resume
practice · Sep 04
Claude Code's --worktree Now Accepts a GitLab Merge Request URL Directly, No Number Conversion Needed
practice · Sep 02
Claude Code's Auto Mode Became the Default on 8/14, and Its Rules Are Now Written as Plain Sentences
practice · Sep 01
Related News
More Related Topics