Permission System for Bash Command Approval and Sandboxing in Reasonix

Reasonix enforces a layered permission hierarchy that evaluates Bash commands through a deny → ask → allow → fallback sequence, combining regex-based access control lists with OS-level sandboxing via Seatbelt or bubblewrap to isolate shell execution from the host filesystem.

The permission system for bash command approval and sandboxing in Reasonix provides fine-grained governance over shell commands executed by the AI agent. According to the esengine/DeepSeek-Reasonix source code, the platform implements a fail-closed security model where write-capable tools default to explicit user approval unless explicitly configured otherwise. This architecture ensures that potentially destructive operations require human verification while maintaining developer productivity through configurable automation.

Permission Hierarchy and Evaluation Order

Every tool invocation in Reasonix traverses a strict evaluation sequence defined in site/src/pages/docs.astro. The system processes permissions in the following order: deny → ask → allow → fallback.

Read-only tools typically pass automatically, but write-capable tools—including Bash—respect the configured [permissions] mode. The default posture is ask, which triggers an interactive prompt before executing any Bash command that modifies the system.

When evaluating a command, Reasonix checks explicit deny lists first, followed by allow lists. If neither list matches, the system falls back to the global mode setting. This hierarchy ensures that dangerous patterns like rm -rf are blocked immediately, regardless of broader permission settings.

Explicit Deny and Allow Lists

The opencode.json file at the repository root defines global permission defaults and per-tool regex patterns. Administrators can specify wildcard denials ("*": "deny") alongside granular Bash-specific rules.

The configuration uses regex patterns to match command strings. For example, the following rules demonstrate typical security boundaries:


# ~/.reasonix/config.toml

[permissions]
mode = "ask"
deny = ["Bash(rm -rf*)", "Bash(git push*)"]
allow = ["Bash(go test:*)"]

Entries like Bash(rm -rf*) prevent recursive deletion operations, while Bash(go test:*) permits testing workflows without manual approval. These patterns are evaluated against the raw command string before execution, providing deterministic control over shell access.

Dynamic Bash Opt-In for Indirect Execution

By default, Bash commands executed indirectly—such as those spawned by other tools—follow the standard permission flow. Setting allow_dynamic_bash = true in the [permissions] section modifies this behavior to permit indirect Bash execution when the global mode is set to allow.

As documented in site/src/pages/docs.astro, this opt-in prevents accidental shell escapes through tool chains while enabling sophisticated automation workflows. Without this flag, even indirect Bash invocations respect the deny/ask/allow hierarchy, ensuring that write operations cannot bypass user consent through intermediary tools.

Sandboxing Architecture and Filesystem Restrictions

Workspace Isolation and Path Resolution

All file-writing tools, including Bash when spawning subshells, must operate within the configured [sandbox] workspace_root. By default, this resolves to the current working directory. The sandbox implementation resolves symlinks and normalizes .. path segments to prevent directory traversal attacks.

The configuration supports explicit read and write restrictions:

[sandbox]
workspace_root = ""                  # Empty string defaults to current directory

allow_write = ["/tmp"]               # Writable paths inside the sandbox

forbid_read = ["${HOME}/.ssh"]       # Paths blocked from read access

OS-Level Sandbox Enforcement

Reasonix supports mandatory OS-level isolation through the bash configuration option, which accepts "enforce" or "off". When set to "enforce" and a compatible backend is present—Seatbelt on macOS or bubblewrap on Linux—Bash commands execute within a restricted environment isolated from the host filesystem.

If enforcement is enabled but no sandbox backend is available, Reasonix rejects the Bash command rather than executing it unconfined. This fail-closed behavior, described in site/src/pages/docs.astro, prevents accidental exposure of sensitive system resources when security dependencies are missing.

Headless Execution Safety Controls

The reasonix run command defaults to the Ask posture for all write-capable operations. In headless or CI environments, Bash commands will fail closed unless explicitly authorized via command-line flags.

To enable automated execution, supply one of the following options:


# Auto-approve safe commands in headless mode

reasonix run -y "go test ./..."

# Or use the explicit permission mode flag

reasonix run --permission-mode auto "build_script.sh"

Without these flags, any Bash invocation requiring write access terminates with a permission error rather than hanging indefinitely for user input. This design ensures that unattended runs cannot invoke destructive shell commands without explicit configuration.

Summary

  • Hierarchical evaluation: Reasonix processes permissions as deny → ask → allow → fallback, with Bash defaulting to the ask mode unless explicitly configured.
  • Regex-based ACLs: The opencode.json and config.toml files support pattern-based deny and allow lists for precise command filtering.
  • Indirect execution control: The allow_dynamic_bash setting governs whether indirect Bash calls (from other tools) respect the allow mode or require explicit approval.
  • Filesystem sandboxing: The workspace_root parameter confines all write operations, with symlink resolution and path normalization preventing directory escape.
  • OS-level isolation: Setting bash = "enforce" requires Seatbelt (macOS) or bubblewrap (Linux); commands fail rather than run unconfined if backends are unavailable.
  • Headless safety: reasonix run defaults to interactive approval; automated workflows require -y, --auto, or --permission-mode auto to proceed.

Frequently Asked Questions

How does Reasonix determine whether to prompt for Bash command approval?

Reasonix evaluates every Bash command against the permission hierarchy defined in site/src/pages/docs.astro. First, it checks explicit deny lists (blocking matches immediately), then allow lists (auto-approving matches). If no pattern matches, it falls back to the global mode setting—defaulting to ask, which triggers an interactive prompt before execution.

What configuration files control Bash permissions and sandboxing?

Permissions are defined in opencode.json at the repository level for global defaults, and in ~/.reasonix/config.toml or project-local reasonix.toml for runtime settings. The [permissions] section controls approval modes and regex patterns, while the [sandbox] section defines workspace_root and path restrictions. OS-level enforcement is toggled via the [tools] bash setting.

Can Reasonix block Bash commands executed indirectly by other tools?

Yes. Without allow_dynamic_bash = true in the [permissions] section, Bash commands spawned indirectly (e.g., by another tool invoking a shell) still traverse the deny/ask/allow hierarchy. Enabling this setting allows the allow mode to cover indirect execution, while deny rules remain enforced regardless of this flag.

What happens if the OS-level sandbox backend is unavailable?

When bash = "enforce" is configured but Reasonix cannot detect Seatbelt (macOS) or bubblewrap (Linux), the system rejects the Bash command entirely rather than executing it without sandboxing. This fail-closed behavior ensures that security policies are never silently degraded due to missing dependencies.

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 →