google-gemini / google-gemini/gemini-cli

bug: commandRegex policy patterns are unanchored and can match across JSON properties

Open
#29,053 0 comments 0 reactions 0 assignees View on GitHub
area/enterprise status/need-triage
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.