Skip to content

Protect Shell Tools

Shell access is one of the highest-risk capabilities an agent can have. A single rm -rf, curl | bash, or chmod 777 can cause irreversible damage. This guide shows how to gate shell tools with ShadowAudit.

Basic shell policy

# policies/shell_agent.yaml

deny:
  - capability: shell.execute
    contains: "rm -rf"
  - capability: shell.execute
    contains: "curl | bash"
  - capability: shell.execute
    contains: "wget | sh"
  - capability: shell.execute
    contains: "chmod 777"
  - capability: shell.execute
    contains: "> /dev/null 2>&1 &"
  - capability: shell.root_access

require_approval:
  - capability: shell.execute
    contains: "systemctl"
  - capability: shell.execute
    contains: "apt-get install"
  - capability: shell.execute
    contains: "pip install"
  - capability: filesystem.write
    path_prefix: "/etc"
  - capability: filesystem.write
    path_prefix: "/usr"

allow:
  - capability: shell.execute
  - capability: filesystem.read

LangChain integration

from shadowaudit import ShadowAuditTool
from langchain.tools import ShellTool

safe_shell = ShadowAuditTool(
    tool=ShellTool(),
    agent_id="ops-agent",
    capability="shell.execute",
    policy_path="policies/shell_agent.yaml"
)

# Use safe_shell wherever you'd use ShellTool
tools = [safe_shell]

Direct gate integration

import subprocess
from shadowaudit.core.gate import Gate

gate = Gate()

def safe_run(command: str, agent_id: str) -> str:
    result = gate.evaluate(
        agent_id=agent_id,
        task_context="shell",
        risk_category="shell_execution",
        capability="shell.execute",
        policy_path="policies/shell_agent.yaml",
        payload={"command": command}
    )
    if not result.passed:
        raise PermissionError(f"Blocked: {result.reason}")
    return subprocess.check_output(command, shell=True, text=True)

What to watch in the audit log

After running your agent, review decisions:

shadowaudit logs --audit-log audit.db --json

Use these findings to refine your policy: add explicit deny rules for patterns you see, and tighten require_approval thresholds.

Scanning existing codebases

Before adding ShadowAudit, identify which shell tools are currently ungated:

shadowaudit check ./src --framework langchain

This reports tools that are exposed to an agent without a ShadowAudit wrapper.