How to Restrict Shell Commands in the aisuite Shell Toolkit

The aisuite Shell Toolkit provides configurable sandbox controls via allowed_commands, allow_all, and allow_shell parameters to whitelist specific binaries and block dangerous shell operators.

The aisuite library by Andrew Ng offers a secure shell execution environment through its ShellToolkit class. When building AI agents that require system command execution, restricting shell commands in the aisuite shell toolkit prevents unauthorized access and potential security vulnerabilities. This guide examines the validation mechanisms implemented in aisuite/toolkits/shell.py to help you configure strict command sandboxing.

Configuration Parameters for Command Restrictions

The ShellToolkit constructor accepts several security parameters that control command execution privileges. According to the source code in aisuite/toolkits/shell.py, you must provide either an allowed_commands whitelist or set allow_all=True, otherwise the constructor raises a ValueError at lines 64-68.

Whitelisting with allowed_commands

The allowed_commands parameter accepts a list of exact command strings or prefixes that define which binaries may execute. When run_shell processes a command, the _validate_command method compares the input against this whitelist, raising a PermissionError if no match is found.

from aisuite import toolkits as tk

# Only permit python3 and ls commands

tools = tk.shell(
    cwd="/tmp",
    allowed_commands=["python3", "ls"],
    allow_all=False,
    allow_shell=False,
)

run_shell = tools[0].func

# ✅ Allowed: matches whitelist

result = run_shell("python3 -c 'print(\"hello\")'")
print(result["stdout"])  # → hello

# ❌ Blocked: raises PermissionError

run_shell("git status")

Disabling Restrictions with allow_all

Setting allow_all=True bypasses the whitelist validation entirely. The _validate_command method short-circuits when this flag is enabled, permitting any system command to execute regardless of the allowed_commands content.

Blocking Shell Operators with allow_shell

The allow_shell parameter controls whether the toolkit accepts shell-specific syntax such as pipes (|), redirections (>), and logical operators (&&). When set to False, the _validate_no_shell_syntax method scans for prohibited tokens including newlines and metacharacters, raising a ValueError if detected.

tools = tk.shell(
    cwd=".",
    allowed_commands=["make"],
    allow_shell=False,  # Reject &&, |, > etc.

)

run_shell = tools[0].func

# Allowed: single command with arguments

run_shell("make build")

# Blocked: raises ValueError for shell syntax

run_shell("make build && echo done")

Internal Validation Flow

The restriction logic follows a multi-layer validation pipeline before executing any command via subprocess.run.

First, the constructor validates that either allowed_commands is populated or allow_all is enabled. Then, during command execution, run_shell invokes validation methods in sequence. If allow_shell=False, the code parses the command using shlex.split and checks for shell metacharacters. Finally, if allow_all=False, the command string is checked against the whitelist. Only commands passing both validation stages proceed to subprocess.run.

Practical Implementation Examples

Basic Agent Integration

When integrating the shell toolkit into an AI agent, configure strict permissions to limit the agent's system access:

import aisuite as ai

# Build a tool set restricted to pytest only

tool_set = ai.toolkits.shell(
    cwd="tests",
    allowed_commands=["pytest"],
    allow_shell=False,
)

assistant = ai.Agent(
    name="tester",
    model="openai:gpt-4o",
    tools=[tool_set[0]],
)

Strict Sandbox Configuration

For maximum security, combine all restriction parameters:

tools = tk.shell(
    cwd="/sandbox",
    allowed_commands=["python3", "pip"],
    allow_all=False,      # Enforce whitelist strictly

    allow_shell=False,    # Disable pipes and redirection

    default_timeout_seconds=30,
    max_output_chars=10000,
)

Summary

  • The allowed_commands parameter creates a whitelist of permitted binaries, enforced by the _validate_command method in aisuite/toolkits/shell.py.
  • Setting allow_all=True disables whitelist enforcement, allowing unrestricted command execution.
  • When allow_shell=False, the toolkit rejects pipes, redirections, and other shell operators via _validate_no_shell_syntax.
  • The constructor requires explicit configuration of either a whitelist or allow_all mode to prevent accidental unrestricted access.
  • Commands are validated using shlex.split before execution to ensure proper tokenization when shell mode is disabled.

Frequently Asked Questions

What happens if I don't specify allowed_commands or allow_all?

The ShellToolkit constructor raises a ValueError if neither parameter is provided, ensuring that developers explicitly configure the security model rather than defaulting to unrestricted access.

Can I use wildcards or regex in the allowed_commands list?

The current implementation in aisuite/toolkits/shell.py performs prefix matching rather than regex evaluation. Commands must match exactly or start with one of the entries in the allowed_commands list.

How does aisuite prevent command injection when allow_shell is False?

The toolkit uses shlex.split to tokenize the command string and the _validate_no_shell_syntax method checks for prohibited characters including pipes, ampersands, and redirection operators. Any detected shell syntax triggers a ValueError before the command reaches subprocess.run.

Where is the shell restriction logic implemented in the source code?

All validation logic resides in aisuite/toolkits/shell.py, specifically within the _validate_command method (lines 13-22) for whitelist enforcement and _validate_no_shell_syntax (lines 23-30) for shell operator detection.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →