Skip to main content
Declaw uses Firecracker — an open-source microVM monitor developed by AWS — to provide hardware-level isolation for each sandbox. Each sandbox is a separate VM with its own Linux kernel, memory, and I/O devices. The boot time is approximately 125 milliseconds.

VM structure

Rootfs isolation

Each sandbox gets an independent rootfs through Linux OverlayFS:
  1. Base image (/opt/declaw/rootfs/rootfs.ext4): Read-only ext4 image shared across all sandboxes. Contains the OS, packages, and tools from the selected template.
  2. Overlay image (/opt/declaw/run/<sandbox_id>/overlay.ext4): Per-sandbox writable ext4 image. All writes go here. Deleting a sandbox deletes only this file.
  3. OverlayFS mount: The VM sees the merged view — the base image as the lower layer and the overlay as the upper layer.
/opt/declaw/run/sbx-abc123/
├── overlay.ext4       # writable per-sandbox layer (fast-formatted at creation)
├── fc.sock            # Firecracker API socket
├── fc.log             # Firecracker VM logs
└── ca.pem             # per-sandbox CA cert (if PII/injection enabled)

Sandbox ID validation

Sandbox IDs must match the pattern sbx-[a-z0-9][a-z0-9-]{0,63} before they are used in any filesystem path. The orchestrator rejects IDs containing .., /, or any path separator. This prevents path traversal attacks where a crafted sandbox ID like sbx-../../../etc could resolve to an unintended directory.
// From infra/orchestrator/internal/sandbox/firecracker.go
var validSandboxID = regexp.MustCompile(`^sbx-[a-z0-9][a-z0-9-]{0,63}$`)

func ValidateSandboxID(id string) error {
    if !validSandboxID.MatchString(id) {
        return fmt.Errorf("invalid sandbox ID %q", id)
    }
    if strings.Contains(id, "..") || strings.Contains(id, "/") {
        return fmt.Errorf("invalid sandbox ID %q: contains path traversal", id)
    }
    return nil
}

Network setup

Each sandbox gets a dedicated Linux network namespace (ns-sbx-<id>) with:
  • veth pair: One end in the host network namespace (for routing), one end in the sandbox namespace.
  • TAP device: Inside the sandbox namespace, bridges the namespace to the Firecracker VM’s virtual NIC.
  • iptables rules: Applied to the veth interface in the sandbox namespace for CIDR-based network policies.
Host namespace
└── veth0 (172.20.0.1/30)

Sandbox namespace (ns-sbx-abc123)
├── veth0 (172.20.0.2/30)
├── tap0  (172.16.0.1/24)
└── iptables REDIRECT rules

Firecracker VM
└── eth0 (172.16.0.2/24, gateway 172.16.0.1)

Network slot pool

The orchestrator maintains a pool of 256 pre-allocated network slots. Each slot includes a pre-created network namespace, veth pair, and TAP device. When a sandbox is created, a slot is claimed from the pool (instant), and the pool replenishes in the background. This eliminates networking setup time from the sandbox creation hot path.

Boot process

Cold boot time from CreateVM() call to envd ready is approximately 125 milliseconds. With snapshot restore, it drops to approximately 30 milliseconds.

Resource defaults

ResourceDefaultRange
vCPUs11–8
Memory256 MB128 MB–8 GB
Disk (overlay)20 GB ext4Fixed
Boot time~125 ms cold~30 ms from snapshot

Concurrency limits

The FirecrackerManager enforces two semaphores to prevent resource exhaustion:
  • Create semaphore: Maximum 1024 concurrent sandbox creations. Prevents OOM when many sandboxes start simultaneously.
  • Exec semaphore: Set to 4 × CPU cores (e.g., 128 slots on a 32-core machine). Limits concurrent fork+exec calls to reduce CPU contention during parallel sandbox creation.

envd: the in-VM daemon

envd is a Go binary that starts as PID 1 inside every Firecracker VM. It exposes a ConnectRPC server on port 49983 (accessible via the TAP/veth bridge from the host) with three service groups:
ServiceMethods
FilesystemRead, Write, WriteBatch, ListDir, Exists, Info, Remove, Rename, MakeDir, Watch
ProcessStart, Wait, Kill, SendStdin, List
PTYCreate, Kill, SendStdin, Resize
All communication between the SDK and the sandbox goes through the orchestrator, which relays ConnectRPC calls to envd via the private veth pair. This traffic never crosses the public network.

Snapshot mechanism

When create_snapshot() is called:
  1. The VM is briefly paused (CRIU-style memory dump)
  2. The memory image and overlay diff are written to GCS (GCP) or S3 (AWS)
  3. The VM resumes
When restoring from a snapshot:
  1. A fresh network slot is claimed
  2. The memory image and overlay are downloaded and placed in the sandbox directory
  3. Firecracker restores the VM from the memory image (~30 ms)
  4. envd is already running — no boot phase