Isolation Model
How Runra Sandbox isolates execution — VM-backed sandboxes, file system isolation, process isolation, resource limits, network policy, and timeout controls
Runra Sandbox provides VM-backed isolation for every sandbox. This means each sandbox runs in its own virtual machine, not just a container — giving you stronger security boundaries than container-based solutions.
VM-backed execution
Each sandbox runs inside a dedicated VM provisioned by CubeSandbox, the open-source engine that powers Runra. This provides:
- Kernel-level isolation: Separate kernel instances prevent privilege escalation between sandboxes
- No shared OS state:
/proc,/sys, and other kernel interfaces are sandbox-private - Guaranteed resource allocation: CPU cores and memory pages are assigned per VM, not shared
┌─────────────────────────────────────────────┐
│ Host Node │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Sandbox A│ │ Sandbox B│ │ Sandbox C│ │
│ │ VM #1 │ │ VM #2 │ │ VM #3 │ │
│ │ CPU: 2 │ │ CPU: 4 │ │ CPU: 8 │ │
│ │ RAM: 4GB │ │ RAM: 8GB │ │ RAM:16GB │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ↕ ↕ ↕ │
│ ┌──────────────────────────────────────┐ │
│ │ CubeProxy (network layer) │ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
File system isolation
Every sandbox gets its own private filesystem workspace. There is no shared filesystem between sandboxes:
const sandboxA = await runra.sandboxes.create({ image: "node:22" });
const sandboxB = await runra.sandboxes.create({ image: "node:22" });
await sandboxA.files.write("/workspace/secret.txt", "token-abc");
await sandboxB.files.write("/workspace/secret.txt", "token-xyz");
// Each sandbox only sees its own file
const a = await sandboxA.files.read("/workspace/secret.txt"); // "token-abc"
const b = await sandboxB.files.read("/workspace/secret.txt"); // "token-xyz"
Workspace structure
/workspace/ ← Your sandbox workspace (persisted across pause/resume)
├── app/ ← Your application code
├── node_modules/ ← Dependencies (preserved on pause)
└── ...
/tmp/ ← Ephemeral temp (cleared on sandbox restart)
File operations
All standard file operations go through the sandbox API:
// Write a file
await sandbox.files.write("/workspace/app.ts", content);
// Read a file
const content = await sandbox.files.read("/workspace/app.ts");
// List directory
const files = await sandbox.files.list("/workspace");
// Check if exists
const exists = await sandbox.files.exists("/workspace/app.ts");
// Delete a file
await sandbox.files.delete("/workspace/temp.log");
// Create directory
await sandbox.files.mkdir("/workspace/src/components");
Process isolation
Processes in one sandbox cannot see or interact with processes in another:
// Sandbox A runs a server
await sandboxA.exec("python -m http.server 8000 &");
// Sandbox B cannot see the server process
const result = await sandboxB.exec("ps aux");
// Shows only sandbox B's processes — no http.server from sandbox A
Each sandbox has its own PID namespace, mount namespace, and IPC namespace — standard Linux namespace isolation reinforced by the VM boundary.
Resource limits
Every sandbox has hard resource limits that cannot be exceeded:
| Resource | Default | Max | Description |
|---|---|---|---|
| CPU cores | 2 | 8 | Dedicated vCPUs |
| Memory | 4096 MB | 16384 MB | Hard limit, OOM kill on exceed |
| Disk | 10240 MB | 51200 MB | Workspace storage |
| Processes | 256 | 1024 | Max simultaneous processes |
const sandbox = await runra.sandboxes.create({
image: "node:22",
resources: {
cpu: 4, // 4 dedicated vCPUs
memoryMb: 8192, // 8 GB RAM (hard limit)
diskMb: 20480, // 20 GB disk
},
});
If a sandbox exceeds its memory limit, the kernel OOM killer terminates the offending process. If CPU usage is sustained at 100%, the VM is throttled to its allocated cores — no noisy neighbor problems.
Network policy
Network access is controlled per sandbox:
const sandbox = await runra.sandboxes.create({
image: "node:22",
network: {
// Allow outbound to specific hosts
egress: {
allow: ["github.com", "registry.npmjs.org", "api.openai.com"],
// Block everything else
default: "deny",
},
// Inbound is only through exposed ports
ingress: {
allowPorts: [3000, 8080],
},
},
});
Default network policy
| Direction | Default | Description |
|---|---|---|
| Outbound (egress) | Allow all | Sandbox can reach any internet host |
| Inbound (ingress) | Deny all | Only ports explicitly exposed are accessible |
| Sandbox-to-sandbox | Deny | Sandboxes cannot communicate with each other |
Port exposure
Only explicitly exposed ports are reachable from the internet:
// Expose port 3000 — generates a public URL
const port = await sandbox.exposePort(3000);
console.log(port.url); // https://3000-abc123.box.runra.dev
See Exposing Ports for the full port exposure guide.
Timeout and lifecycle controls
Prevent runaway sandboxes with automatic lifecycle controls:
const sandbox = await runra.sandboxes.create({
image: "node:22",
timeoutMs: 300_000, // Auto-terminate after 5 minutes (hard limit)
idleTimeoutMs: 120_000, // Auto-pause after 2 minutes of inactivity
});
Timeout types
| Timeout | Trigger | Action |
|---|---|---|
timeoutMs | Total sandbox lifetime exceeded | Force terminate |
idleTimeoutMs | No exec calls for specified duration | Auto-pause |
| Per-command timeout | Individual exec() takes too long | Abort command, sandbox stays running |
// Per-command timeout
const result = await sandbox.exec("npm run long-build", {
timeoutMs: 60_000, // Kill if build takes more than 60 seconds
});
Disposable environments
Every sandbox is disposable by design. Terminate cleans up all resources immediately:
await sandbox.terminate();
// VM destroyed, disk wiped, ports released, IP recycled
No data persists after termination. If you need state to survive, use pause instead.
Security guarantees
Runra Sandbox provides these security guarantees:
- No cross-sandbox access: Sandbox A cannot read Sandbox B's files, processes, or network traffic
- No host escape: VM isolation prevents escape to the host node
- No resource stealing: Hard resource limits prevent one sandbox from starving others
- No persistent side effects: Termination wipes everything
- Network control: You control what each sandbox can reach
Next steps
- Pause & Resume — state preservation without active risk
- Exposing Ports — secure network exposure
- Setup Guide — configure resource limits in production