You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Cursor runner: constrained Bash(...) rules are blocked at preToolUse Shell gate #1423
When using the Cursor runner with constrained Bash permissions such as Bash(git:*) or Bash(npm:*), the session is blocked at Cursor's preToolUse hook before the command-level permission can be evaluated.
This appears inconsistent with the documented Cyrus allowedTools semantics, where patterns like Bash(git:*) are shown as the intended way to allow only Git commands.
Trigger a GitHub-driven Cursor session whose first shell command is for example:
git branch --show-current && git status
Observed failure:
Cyrus blocked: no allow rule matched
(event=preToolUse, candidates=[{"kind":"Tool","value":"Shell"}])
The command never reaches the beforeShellExecution gate where the constrained Bash(git:*) rule could be evaluated.
Expected behavior
Bash(git:*) should allow the Shell tool at the generic preToolUse stage, while still restricting the concrete command at beforeShellExecution to matching Git commands only.
Conceptually:
preToolUse:
Tool(Shell) -> allow because at least one Bash(...) rule exists
beforeShellExecution:
git status -> allow
npm run lint -> allow if Bash(npm:*) exists
rm -rf ... -> deny
Current implementation detail
In packages/cursor-runner/src/permissions.ts, a bare Bash maps to:
Tool(Shell)
Shell(*)
but a constrained rule such as Bash(git:*) maps only to command-level patterns such as:
Shell(git)
Shell(git:*)
so it does not satisfy the earlier preToolUse candidate Tool(Shell).
This is reproducible with the current Cursor permission helper and matches the runtime error above.
Why this matters
Adding bare Bash is not an acceptable workaround for a least-privilege setup, because it also expands to Shell(*), effectively allowing unrestricted shell commands.
The documented configuration examples include constrained rules such as:
["Read", "Edit", "Bash(git:*)", "Task"]
so constrained Bash permissions should work with the Cursor runner without requiring unrestricted Bash.
Suggested direction
For constrained Bash(...) / Shell(...) rules, consider also emitting Tool(Shell) for the generic preToolUse gate, while keeping the command-level allow list constrained.
There may also be value in reviewing whether emitting both Shell(git) and Shell(git:*) is intentionally broad, since the helper currently allows when any candidate matches.
Happy to provide additional logs or test cases if useful.
Root cause:
The permission helper uses the same glob matcher for file paths and Shell patterns. * is translated to [^/]*, which is appropriate for path-style matching but means Shell(git:*) does not match command arguments containing /.
Local fix:
keep existing path semantics for Read/Write patterns
for Shell patterns, let * match / as well
additionally reject obvious shell composition (&&, ;, |, redirects, backticks, $() so a constrained Shell(git:*) rule does not trivially become a general shell escape
Verification:
cursor-runner tests: 52/52 passed
real GitHub/Cyrus/Cursor TASK RUN successfully completed git add, git commit, and git push
Local commit: 98b33513 fix(cursor): allow slashes in constrained shell args safely
Activity
kolli-habee commentedon Aug 22, 2026
Additional finding after fixing the
preToolUsegate:The constrained Shell pattern still fails for commands whose arguments contain
/, for example:Root cause:
The permission helper uses the same glob matcher for file paths and Shell patterns.
*is translated to[^/]*, which is appropriate for path-style matching but meansShell(git:*)does not match command arguments containing/.Local fix:
*match/as well&&,;,|, redirects, backticks,$() so a constrainedShell(git:*)rule does not trivially become a general shell escapeVerification:
TASK RUNsuccessfully completedgit add,git commit, andgit pushLocal commit:
98b33513 fix(cursor): allow slashes in constrained shell args safely