Skip to content

bug(policy): shell tool registers as tool_id='bash', not 'shell' — policy rules silently miss #1877

@bug-ops

Description

@bug-ops

Summary

The shell executor registers itself under tool_id = "bash" (via ToolDef { id: "bash".into(), ... } in shell.rs:533), but users writing policy rules would intuitively use tool = "shell". This causes all shell policy rules to silently not match — shell calls fall through to default_effect.

Reproduction

Config with [tools.policy] enabled = true, default_effect = "allow" and rule tool = "shell", effect = "deny", args_match = "/etc/":

[[tools.policy.rules]]
effect = "deny"
tool = "shell"
args_match = "/etc/"

Running /policy check bash {"command":"cat /etc/passwd"} returns:

Deny: default: deny (no matching rules)   # falls to default, not the deny rule

The deny rule never fires because "shell" != "bash".

With tool = "bash" the rule fires correctly:

Deny: rule[0] deny: tool=bash matched bash

Impact

  • Users configuring shell policy rules with tool = "shell" get silently incorrect behavior
  • Security-critical: if default_effect = "allow", deny rules for "shell" never block

Fix options

  1. Rename shell ToolDef id from "bash" to "shell" (breaking change for LLM context)
  2. Accept both "bash" and "shell" in execute_tool_call and policy matching (via alias)
  3. Add a warning in /policy status when a rule references an unknown tool id
  4. Document in config examples to use tool = "bash" for shell

Observed during

Live testing of PR #1870 (policy enforcer) with config:

[[tools.policy.rules]]
effect = "allow"
tool = "shell"      # ← WRONG: should be "bash"
paths = ["/tmp/*"]

All shell calls were denied by default_effect despite the allow rule.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsecuritySecurity-related issue

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions