Skip to content

Sandboxing Architecture

Autobot uses kernel-level sandboxing to safely restrict LLM file access. Each operation spawns a sandboxed process via bubblewrap or Docker.

Overview

┌──────────────────────────────────────────────────────┐
│ Sandbox.exec                                          │
│  • Works everywhere, zero setup                       │
│  • Single binary                                      │
│  • Spawns sandbox per operation                       │
│  • Uses shell commands (cat, ls, base64)             │
└──────────────────────────────────────────────────────┘

How It Works

Instead of spawning a persistent server, we spawn a sandboxed process for each operation:

# Read file
Sandbox.exec("cat #{shell_escape(path)} 2>&1", workspace, timeout: 10)

# Write file (using base64 to avoid escaping issues)
encoded = Base64.strict_encode(content)
Sandbox.exec("printf '%s' '#{encoded}' | base64 -d > #{shell_escape(path)}", workspace, timeout: 30)

# List directory
Sandbox.exec("ls -1a #{shell_escape(path)} 2>&1", workspace, timeout: 10)

Why Shell Commands?

  • Alpine container has /bin/sh built-in - no binary compatibility issues
  • We pass strings, not binaries - works everywhere
  • Works in Docker/bubblewrap/any Linux container
  • Simple and reliable

Execution (Linux - bubblewrap)

bwrap \
  --ro-bind /usr /usr \
  --ro-bind /bin /bin \
  --bind /workspace /workspace \
  --unshare-all \
  --proc /proc \
  --dev /dev \
  --chdir /workspace \
  -- sh -c "cat file.txt"

Execution (macOS/Universal - Docker)

docker run --rm \
  -v /workspace:/workspace:rw \
  -w /workspace \
  --memory 512m --cpus 1 \
  alpine:latest \
  sh -c "cat file.txt"

Platform Support

Platform Sandbox Tool
Linux bubblewrap (recommended)
Linux Docker
macOS Docker
Windows Docker (WSL2)

Installation

# Ubuntu/Debian
sudo apt install bubblewrap

# Fedora
sudo dnf install bubblewrap

# Arch
sudo pacman -S bubblewrap

macOS (Requires Docker)

# Docker Desktop required
# Download from: https://docs.docker.com/desktop/install/mac-install/

# Verify
docker run --rm alpine:latest echo "Sandbox ready"

Why Docker on macOS?

  • macOS sandbox-exec only restricts writes, NOT reads
  • Can't prevent reading /etc/passwd, ~/.ssh/, etc.
  • Docker provides full read+write isolation
  • Apple is deprecating sandbox-exec anyway

Windows (Docker via WSL2)

# Install Docker Desktop with WSL2 backend
# https://docs.docker.com/desktop/windows/wsl/

# Verify
docker run --rm alpine:latest echo "Sandbox ready"

Configuration

Configure sandboxing in config.yml:

tools:
  sandbox: auto  # auto | bubblewrap | docker | none (default: auto)
  docker_image: "python:3.14-alpine"  # optional, overrides Dockerfile.sandbox
  sandbox_env:   # env vars to forward into Docker sandbox (default: none)
    - HA_URL
    - MQTT_HOST

Options:

  • sandbox — Sandbox backend
  • auto - Auto-detect best available (recommended)
  • bubblewrap - Force bubblewrap (Linux only)
  • docker - Force Docker (all platforms)
  • none - Disable sandboxing (UNSAFE - tests only)
  • docker_image — Docker image to use for sandbox containers. Overrides Dockerfile.sandbox when set. Only applies when sandbox is docker or auto resolves to Docker.
  • sandbox_env — List of environment variable names to forward into Docker containers. Only listed variables are forwarded — empty by default for security. Useful when sandbox scripts need access to specific env vars (e.g. HA_URL, MQTT_HOST).

Custom sandbox image (Dockerfile.sandbox)

When using Docker sandbox, the default alpine:latest image only includes basic shell tools. To add runtimes your bot needs (Python, SQLite, GitHub CLI, etc.), create a Dockerfile.sandbox in your bot folder:

# Dockerfile.sandbox
FROM alpine:latest

RUN apk add --no-cache \
    python3 \
    curl \
    sqlite \
    git \
    github-cli

Autobot automatically builds and caches this as autobot-sandbox on first run. To rebuild after changes:

docker build -t autobot-sandbox -f Dockerfile.sandbox .

Priority order:

  1. tools.docker_image in config.yml (explicit override)
  2. Dockerfile.sandbox in bot folder (auto-built)
  3. alpine:latest (default fallback)

Note: autobot new generates a default Dockerfile.sandbox with common tools. Edit it to match your needs.

Note: This only applies to Docker sandbox. With bubblewrap, host-installed tools are available automatically.

Security Properties

What Sandboxing Prevents

  • Reading system files (/etc/passwd, /etc/shadow)
  • Reading home directory (~/.ssh/, ~/.aws/credentials)
  • Writing outside workspace
  • Accessing secrets in parent directories
  • Path traversal attacks (../../../etc/passwd)
  • Absolute path exploits (/etc/passwd)

How It Works

All filesystem and exec operations go through SandboxExecutor, which routes them to Sandbox.exec. Each operation spawns a sandboxed process (bubblewrap or Docker) that cannot access files outside the workspace — enforced by the OS kernel, not application code.

Shell escaping (single-quote escaping, base64 encoding for file content) prevents command injection within sandboxed commands.

Note: Plugin tools that call external CLIs (e.g. gh, curl) use Process.run with argument arrays (no shell interpretation) and run outside the sandbox since they need host resources (auth configs, SSL certs).

What Sandboxing Does NOT Prevent

  • Network attacks (agent has network access)
  • API key theft (main process has keys)
  • DoS via API calls
  • Social engineering (user approves actions)

Defense in depth: Use API key scoping, rate limiting, and audit logs.

Troubleshooting

Error: "No sandbox tool found"

Problem: No sandboxing tool installed

Fix:

# Linux: Install bubblewrap
sudo apt install bubblewrap

# macOS/Windows: Install Docker
# https://docs.docker.com/engine/install/

Error: "Failed to start sandbox"

Problem: Binary or configuration issues

Fix:

# 1. Verify tools are installed
which bwrap    # Linux
which docker   # macOS/Windows

# 2. Check workspace exists
ls -ld /path/to/workspace

# 3. Try Docker fallback
autobot agent --sandbox docker

Development

Running Without Sandbox (Tests)

Tests automatically disable sandboxing:

# Tests pass nil workspace to SandboxExecutor
executor = SandboxExecutor.new(nil)
tool = ReadFileTool.new(executor)

# Tool uses direct file operations (fast, no overhead)
tool.execute({"path" => JSON::Any.new("test.txt")})  # Direct File.read

Testing Sandbox Behavior

# spec/security_spec.cr tests sandbox restrictions
it "prevents reading system files" do
  executor = SandboxExecutor.new(workspace)
  tool = ReadFileTool.new(executor)
  result = tool.execute({"path" => JSON::Any.new("/etc/passwd")})
  result.error?.should be_true
end

FAQ

Q: Does this work on Windows? A: Yes, via Docker with WSL2 backend.

Q: How do I verify sandboxing works? A: Try reading /etc/passwd - should fail with "Absolute paths not allowed"

Q: Can I disable sandboxing? A: Only for tests. Production requires sandboxing for safety.


Summary: Autobot uses kernel-level sandboxing (bubblewrap or Docker) to restrict LLM file access. Each operation spawns a sandboxed process with shell commands, ensuring compatibility across all platforms with zero extra setup.