google-gemini / google-gemini/gemini-cli
bug: commandRegex policy patterns are unanchored and can match across JSON properties
- Dominant language
- TypeScript
- Stars
- 107k
- Forks
- 14.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 45
Description
## What happened?
In `buildArgsPatterns()`, the `commandRegex` branch splices the user-authored regex raw into a JSON-shaped pattern with no boundary anchoring, unlike the carefully bounded `commandPrefix` branch right above it. Because the resulting regex is tested against the **entire stable-stringified args object**, an unescaped `.*`/unterminated match can cross out of the `"command"` value into *subsequent* JSON properties — so allow/deny rules match based on unrelated fields. Symmetrically, a natural leading `^` refers to the start of the whole JSON string rather than the command value, making intuitive patterns silently never match.
## Affected code
`packages/core/src/policy/utils.ts:85-87`:
```ts
if (commandRegex) {
return [`"command":"${commandRegex}`];
}
```
Contrast with the prefix branch (~lines 61-84) which escapes the literal segment and terminates matching at `(?:[\s"]|\\")`.
Consumed by `PolicyEngine.check()` against the full stable-stringified args (`policy-engine.ts:213-218`).
## How can this be reproduced?
Policy: `{ toolName = "run_shell_command", decision = "allow", commandRegex = ".*safe" }`.
Args `{"command":"evil-cmd","dir_path":"C:\\safe"}` → pattern `"command":".*safe` matches (the `.*` spans past the closing quote of `command` into later properties) → allowed although the command itself contains nothing "safe".
Also: `commandRegex = "^git "` never matches anything, since `^` anchors at `{"command":...`, not at the value.
## What did you expect to happen?
`commandRegex` should be confined to the `command` property's value (bounded like `commandPrefix`), or documented as intentionally free-form over the whole args blob.
## Impact
Allow-rules can authorize commands based on unrelated argument content; deny/ask rules can silently never fire.
## Suggested direction
Wrap as `"command":"(?:${commandRegex})(?:[\\s"]|\\\\")"`-style bounded segment (mirroring the prefix branch semantics), or explicitly anchor users' regexes to the value boundaries.
---
*Found by source audit on current `main` (commit `5411f113c`); platform-independent. No open issue/PR covering this was found (searched: commandRegex policy args pattern).*
Contributor guide
Research direction
Start in packages/core/src/policy/utils.ts at buildArgsPatterns(), then read PolicyEngine.check() in policy-engine.ts where the full stable-stringified args are tested. Reproduce the two commandRegex examples from the issue and add coverage showing patterns stay within the command value, including the expected behavior for a leading ^; done means unrelated properties no longer affect allow/deny matching.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- authorization, cli, security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100