−25%

on annual Windows plans, until 31 Oct. See plans

EQVPS
Get started

Container vs microVM isolation: 4 levels compared, from a subprocess to a full VM

Oct 10, 2026 · 6 min read · EQVPS Team

"Run it in a sandbox" sounds like one instruction. In practice there are four common boundaries people mean by it, and they stop very different things. Choosing the wrong one either leaves you exposed or makes every run slower and more expensive than it needs to be.

This comparison assumes the code is genuinely untrusted: written by a language model, submitted by a user, or arriving in a pull request from someone you don't know. Code you wrote yourself has different needs.

What can go wrong

Before comparing boundaries, it helps to name what they're for. Untrusted code can:

  1. Read what it shouldn't: environment variables, SSH keys, files in your home directory, cloud metadata endpoints.
  2. Exhaust resources: loop forever, fork until the machine stalls, fill the disk.
  3. Abuse the network: scan other hosts, send spam, mine cryptocurrency, call your internal services.
  4. Persist: install a cron job or a service that outlives the task.
  5. Escape: use a bug in the layer below to run code on the host itself.

Each level below handles some of these and not others.

Level 1: a process

The simplest sandbox is a child process: subprocess.run with a timeout, perhaps under a separate user, with resource limits and a seccomp filter if you're thorough.

Stops: runaway time (the timeout), some resource exhaustion (limits), some dangerous system calls (seccomp). Doesn't stop: reading anything that user can read, network access, persistence through anything the user can write, and any kernel bug. Typical failure: the code reads a file you forgot was readable, or a "restricted" language interpreter turns out to have an escape hatch. History is full of in-language sandboxes that didn't hold.

Start time is effectively zero. Fine for code you wrote; not a boundary for code you didn't.

Level 2: a container

Namespaces give the code its own view of files, processes and network; cgroups cap CPU and memory; dropped capabilities and seccomp narrow what it can ask the kernel to do.

Stops: reading the host's files (unless mounted), seeing other processes, unlimited resource use, much of the persistence problem if the container is thrown away. Doesn't stop: a bug in the shared host kernel. Every container on the machine talks to the same kernel, so a reachable kernel vulnerability is an exit. Typical failure: configuration rather than exotic exploits. A privileged container, the container runtime's socket mounted inside, host networking switched on "just for debugging". Each one quietly removes the boundary.

Start time is milliseconds. Hardened variants exist, including user-space kernels that intercept system calls before they reach the host, at some cost in speed and compatibility. For code from people you trust, a well-configured container is a sensible default.

Level 3: a microVM

A microVM runs its own kernel under a hypervisor, like a full VM, but with almost all of the emulated hardware removed. Firecracker is the best-known example.

Stops: everything a container stops, plus the shared-kernel problem. To reach the host, code has to break the hypervisor or one of a handful of virtual devices, a much smaller surface than a kernel's system-call interface. Doesn't stop: misuse of whatever you hand it. Open egress can still be abused; secrets you inject can still leak. Typical failure: policy, not isolation. Someone passes a production token "to make the tests work", or leaves outbound traffic unrestricted on a workload that doesn't need it.

Start time is a fraction of a second to about a second, with a few megabytes of overhead. That's fast enough to create one per task and delete it afterwards, which also solves persistence: there is nothing left to come back to.

Level 4: a full virtual machine

A regular VM, or a VPS, has the same kind of boundary as a microVM: hardware virtualisation and a hypervisor. The difference is everything around it: a full device model, a complete OS, a public IP if you want one, and a lifecycle measured in days or months.

Stops: the same classes of problems as a microVM, with a somewhat larger attack surface because more hardware is emulated. Doesn't stop: misuse of its own network identity. A VM with a public IP that runs abusive code gets its IP blocklisted, which matters if that IP also sends your email. (If that's already happened, see what to do when your IP is on a blocklist.) Typical failure: it lives too long. A VM created for one experiment collects credentials and state, and slowly becomes the trusted machine it was meant to protect.

Start time is tens of seconds to minutes, and billing is usually monthly. That's the right shape for a long-running service that needs inbound ports, and the wrong shape for a 20-second code run.

The comparison

ProcessContainerMicroVMFull VM
Own kernelnonoyesyes
Main boundaryuser permissionsnamespaces + shared kernelhypervisor, tiny device modelhypervisor, full device model
Start time~0ms~0.1–1 s10 s – minutes
Overheadnonesmalla few MiBtens–hundreds of MiB
Throw away per taskeasyeasyeasyslow, costly
Inbound ports / public IPhost'shost'susually noneyes

Choosing

  • Code you or your team wrote: a process or container is fine.
  • CI for your own branches: a container on your runner.
  • Agent-generated code, user submissions, outside pull requests: a microVM per task, deleted afterwards.
  • An untrusted service that must accept connections or run for weeks: a separate VM with its own IP, kept away from anything that holds your credentials or sends your mail.

Whatever you pick, two rules apply on top: put nothing inside you wouldn't hand to the author of the code, and decide deliberately what the network may do.

Where our products sit

For level 3 we run code sandboxes: Firecracker microVMs that start in about a second, with outbound internet, no inbound ports and per-second billing. They're aimed at exactly the third bullet above; the MCP guardrails page covers how to limit what an agent may do with them. For level 4, a VPS such as the AI agent plan gives you a whole machine by the month. The worked examples in sandbox for AI agents show the microVM pattern end to end, and what AI agents need from infrastructure looks at isolation as one of several requirements.

FAQ

Is a container enough for running AI-generated code?

For code from your own team, usually. For code nobody has reviewed — an agent's output, user submissions, outside pull requests — a container's shared kernel is the weak point. A microVM or VM puts a hypervisor between that code and the host.

What's the difference between a microVM and a regular VM for isolation?

The boundary is the same kind: hardware virtualisation and a hypervisor. A microVM exposes far fewer virtual devices, so the surface is smaller, and it starts in about a second instead of tens of seconds. A full VM is better for long-running services that need a public IP, more devices or a whole OS.

Does isolation stop code from stealing my API keys?

Only if the keys aren't inside. Isolation protects the host from the code; it doesn't protect secrets you deliberately passed in. Give untrusted code nothing it shouldn't have.

What about network access?

It matters as much as the compute boundary. Decide whether the code needs outbound internet at all, and make sure nothing can connect in. A perfectly isolated machine can still be used to scan, spam or mine if its traffic is unrestricted.

Comments

No comments yet. Be the first.

Leave a comment

Comments are moderated before they appear.