Skip to content

diggerhq/opensandbox

Repository files navigation

OpenSandbox - Linux Sandbox with HTTP API

A Rust implementation of a Linux sandbox that runs commands in isolated environments with namespace separation, resource limits, and optional stateful sessions.

Demo

Coding agent creating a PR in an isolated sandbox:

demooooo.mp4

Features

  • PID namespace isolation - sandboxed processes can't see host processes
  • Mount namespace isolation - sandboxed processes have their own filesystem view
  • Chroot jail - processes are confined to a minimal filesystem
  • Resource limits - CPU time, memory, file size, open files
  • Stateful sessions - files and environment variables persist across requests
  • HTTP API - easy integration with any language/tool
  • gRPC API - high-performance binary protocol for low-latency operations
  • Python SDK - native Python client with async support

Quick Start

# Build and run with Docker
docker compose up --build

# Test it
curl -X POST http://localhost:8080/run \
  -H "Content-Type: application/json" \
  -d '{"command": ["/bin/echo", "Hello from sandbox!"]}'

API Endpoints

Stateless Execution

POST /run - Run a command in a fresh sandbox (cleaned up after)

curl -X POST http://localhost:8080/run \
  -H "Content-Type: application/json" \
  -d '{
    "command": ["git", "--version"],
    "time": 5000,
    "mem": 2097152,
    "fsize": 10240,
    "nofile": 64
  }'

Response:

{
  "stdout": "git version 2.39.2\n",
  "stderr": "",
  "exit_code": 0,
  "signal": null
}

Stateful Sessions

Sessions preserve files and environment variables across multiple requests.

POST /sessions - Create a new session

curl -X POST http://localhost:8080/sessions \
  -H "Content-Type: application/json" \
  -d '{"env": {"MY_VAR": "hello"}}'
# Returns: {"session_id": "uuid..."}

POST /sessions/:id/run - Run command in session

# Write a file
curl -X POST http://localhost:8080/sessions/{id}/run \
  -H "Content-Type: application/json" \
  -d '{"command": ["/bin/sh", "-c", "echo hello > /tmp/test.txt"]}'

# Read it back (file persists!)
curl -X POST http://localhost:8080/sessions/{id}/run \
  -H "Content-Type: application/json" \
  -d '{"command": ["/bin/cat", "/tmp/test.txt"]}'

POST /sessions/:id/env - Set environment variables

curl -X POST http://localhost:8080/sessions/{id}/env \
  -H "Content-Type: application/json" \
  -d '{"env": {"GH_TOKEN": "..."}}'

POST /sessions/:id/cwd - Set working directory

curl -X POST http://localhost:8080/sessions/{id}/cwd \
  -H "Content-Type: application/json" \
  -d '{"cwd": "/tmp"}'

GET /sessions - List all sessions

GET /sessions/:id - Get session info

DELETE /sessions/:id - Delete session and cleanup

Health Check

GET /health - Returns "OK"

Configuration Options

Parameter Default Description
time 5000 CPU time limit in milliseconds
mem 2097152 Memory limit in KB (2GB default for Go programs)
fsize 10240 Max file size in KB
nofile 64 Max open files
env {} Environment variables
cwd "/" Working directory

CLI Mode

The binary also supports direct CLI execution:

sudo ./opensandbox --run --time 1000 --mem 262144 -- /bin/echo "hello"

Available Tools

The sandbox includes:

  • Standard Unix utilities (/bin, /usr/bin)
  • git
  • gh (GitHub CLI)

Architecture

         HTTP Request (8080)              gRPC Request (50051)
              │                                  │
              ▼                                  ▼
      ┌───────────────┐                 ┌───────────────┐
      │  Axum Server  │                 │ Tonic Server  │
      └───────┬───────┘                 └───────┬───────┘
              │                                  │
              └──────────┬───────────────────────┘
                         │
                         ▼
               ┌─────────────────┐
               │  Shared State   │  (Sessions, Sandbox roots)
               └────────┬────────┘
                        │
                        ▼
               ┌─────────────────┐
               │ spawn_blocking  │  (tokio blocking task)
               └────────┬────────┘
                        │
                        ▼
               ┌─────────────────┐
               │  clone() with   │  CLONE_NEWPID | CLONE_NEWNS
               │  namespaces     │
               └────────┬────────┘
                        │
                        ▼
               ┌─────────────────┐
               │  Child Process  │
               │  - chroot       │
               │  - setrlimit    │
               │  - execvpe      │
               └─────────────────┘

Security Notes

  • Requires --privileged Docker flag for namespace operations
  • Processes run as root inside sandbox (privilege dropping disabled due to multi-threading issues)
  • Sandbox isolation via: PID namespace, mount namespace, chroot, resource limits
  • No network namespace isolation (processes can access network)

Building from Source

# Requires Linux
cargo build --release

# Run (requires root)
sudo ./target/release/opensandbox serve --port 8080

Session Lifecycle

  • Sessions auto-expire after 5 minutes of inactivity
  • Expired sessions are cleaned up automatically
  • Each session has its own sandbox directory at /tmp/sandbox-{id}

Deploying to Fly.io

Fly.io runs apps in Firecracker VMs, which provides the necessary privileges for namespace operations.

  1. Install the Fly CLI and login:
curl -L https://fly.io/install.sh | sh
fly auth login
  1. Create fly.toml in the project root:
app = "opensandbox"
primary_region = "ord"

[build]
  dockerfile = "Dockerfile"

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = false
  auto_start_machines = true
  min_machines_running = 1

[checks]
  [checks.health]
    type = "http"
    port = 8080
    path = "/health"
    interval = "10s"
    timeout = "2s"

[[vm]]
  memory = "2gb"
  cpu_kind = "shared"
  cpus = 2
  1. Deploy:
fly launch
  1. Allocate a public IP (if not automatically assigned):
fly ips allocate-v4 --shared
  1. Test:
curl https://your-app-name.fly.dev/health

Benchmarks

See benchmarks/ for full performance comparisons with E2B.

Summary (OpenSandbox gRPC vs E2B Cloud):

Metric OpenSandbox E2B Winner
Sandbox creation 120ms 232ms OpenSandbox 1.9x faster
Command execution 28ms 52ms OpenSandbox 1.9x faster
File write 10ms 34ms OpenSandbox 3.4x faster
File read 9ms 50ms OpenSandbox 5.5x faster
Git clone workflow 756ms 1322ms OpenSandbox 1.7x faster
Concurrency (8x) 27.5/sec 11.8/sec OpenSandbox 2.3x faster

OpenSandbox wins every category with the gRPC SDK and edge deployment.

Python SDK

Install the SDK for high-performance gRPC access:

pip install opensandbox  # or: pip install -e sdk/python

Usage:

from opensandbox import OpenSandbox

async with OpenSandbox("https://your-server.fly.dev") as client:
    sandbox = await client.create()

    # Run commands (fast - uses gRPC)
    result = await sandbox.run("echo hello")
    print(result.stdout)

    # File operations (fast - native, no shell)
    await sandbox.write_file("/tmp/test.py", "print('hello')")
    content = await sandbox.read_file_text("/tmp/test.py")

    await sandbox.destroy()

See sdk/python/README.md for full documentation.

Similar Projects & Inspiration

  • isolate - Sandbox used by the International Olympiad in Informatics (IOI)

About

OpenSandbox - run untrusted code

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •