docs/security/isolation.mdx
The core of microsandbox's security is the boundary between the guest VM and the host. This page covers what that boundary is made of, how the two sides talk, and what runs with which privilege on each side.
Each sandbox is a lightweight virtual machine:
The practical consequence is simple. A workload that exploits a kernel bug gets a compromised guest kernel, which is exactly what the VM is built to contain. Container escapes that rely on a shared host kernel, like namespace breakouts, cgroup tricks, or a kernel privilege escalation reaching the host, have no shared kernel to attack here.
The per-sandbox process runs as the same user that launched it. It does not need to be root:
/dev/kvm, usually through membership in the kvm group. No setuid, no elevated capabilities.A sandbox therefore grants the guest no ambient host privilege. The guest runs under a normal, unprivileged host process, fenced off by the hypervisor.
The guest can touch the host only through paravirtual (virtio) devices. That fixed list is the host-facing attack surface:
| Device | What it carries |
|---|---|
virtio-console | The control channel to agentd |
virtio-net | Network frames into the host network stack |
virtio-fs | Host directories you explicitly mount |
virtio-blk | The root filesystem and any attached disks |
virtio-rng | Entropy |
There is no general-purpose passthrough. No host PCI devices, no host sockets, and no shared memory beyond these devices.
Your application and the msb CLI drive a sandbox over a single control channel: framed messages on virtio-console, spoken by agentd, the agent that runs as PID 1 inside the guest. The host sends requests like run this command, read this file, or open this TCP connection, and the guest streams back the results.
Two properties matter for security:
agentd makes it from inside the guest, subject to the sandbox's network policy. The host never connects to an arbitrary target on the guest's behalf.Inside the guest the default is permissive, and that is intentional, because the VM is the boundary:
agentd runs as PID 1 (root).sudo, and Docker-in-Docker.For defense-in-depth inside the guest, opt into the restricted security profile. It sets no_new_privs, drops the mount-admin capability from user commands, and forces nosuid,nodev on user mounts. It is incompatible with workloads that need those, such as sudo or Docker-in-Docker.
let sb = Sandbox::builder("worker") .image("python") .user("app") .security(SecurityProfile::Restricted) .create() .await?;
```typescript TypeScript
await using sb = await Sandbox.builder("worker")
.image("python")
.user("app")
.security("restricted")
.create();
from microsandbox import Sandbox, SecurityProfile
sb = await Sandbox.create(
"worker",
image="python",
user="app",
security_profile=SecurityProfile.RESTRICTED,
)
sb, err := m.CreateSandbox(ctx, "worker",
m.WithImage("python"),
m.WithUser("app"),
m.WithSecurityProfile(m.SecurityProfileRestricted),
)
msb create python --name worker --user app --security restricted
Sandboxes share no kernel, no writable filesystem layer, no network namespace, and no process tree. Each is its own VM in its own host process, with its own per-sandbox network gateway. Two sandboxes interact only through mechanisms you set up explicitly, like a shared named volume or a published port one connects to. Absent that, they can't see or reach one another.
vCPU count and memory are capped at VM creation and enforced by the VMM, so a guest cannot allocate beyond its memory ceiling or use more vCPUs than assigned. For lifecycle bounds you can set an idle timeout (which reclaims a sandbox when no work is happening) or a maximum duration. A workload can still burn its own allotted CPU and memory, but that self-inflicted slowdown stays within the limits you choose and is not a cross-tenant concern.
The model trusts the hypervisor, the CPU's virtualization extensions, and the small VMM and device implementation to hold the line. A bug that lets a guest break out of the VM into its host process, a VMM or hypervisor escape, is the one class this boundary cannot defend against from the inside. It is exactly the class we most want reported.