top of page

Anthropic Simon Tested smolvm, but the Sandbox Still Needs a Control Plane

Anthropic Simon researcher Simon Willison tested smolvm against one demanding goal, safely executing untrusted Python and JavaScript without network, filesystem, or resource abuse. The experiment hit an immediate conflict. Claude Code for web ran inside a Firecracker guest, while smolvm needed access to hardware virtualization that the guest did not expose.

That failure did not show that smolvm was insecure. It showed that evaluating a microVM inside another restricted virtual machine can fail before the security tests even begin. The distinction matters for teams considering user-provided scripts, AI-generated programs, or automated data transformations.

The sandbox research notes also expose a larger engineering gap. A strong virtual-machine boundary is only one part of a safe code-execution service. Operators still need deadlines, resource accounting, file staging, output controls, monitoring, and cleanup around that boundary.

smolvm offers several useful ingredients. Networking is disabled by default, workloads receive separate guest kernels, and CPU and memory values are configurable. Yet those features do not automatically create a production service for hostile code.

The real contest is therefore not smolvm against Docker, or Python against JavaScript. It is the promise of one-command isolation against the operational controls required for dependable multi-user execution.

The Test Failed Before the Untrusted Code Ran

The first result was an environment compatibility failure, not a sandbox escape or a failed resource limit.

Willison asked an Anthropic model operating through Claude Code for web to investigate smolmachines as a fast sandbox. The proposed workload was concrete: run code supplied by users for jobs such as transforming structured data.

That code needed strict boundaries. It should see no network, access only designated files, consume bounded memory, and stop after an operator-defined interval. An infinite loop, such as while true, should not occupy compute indefinitely.

The model could research the project and design tests. It could not start the smolvm machines needed to execute them. According to Willison’s account, the Claude Code environment was already a Firecracker guest running Linux.

smolvm uses hardware-assisted virtualization through platform-specific hypervisors. On Linux, that normally means KVM, the kernel interface that exposes processor virtualization features to a virtual-machine monitor. A restricted cloud guest often lacks the /dev/kvm device needed to launch another hardware-accelerated guest.

This is the nested virtualization problem. A virtual machine can host another virtual machine only when the outer platform exposes the necessary processor features and device access. Many managed sandboxes intentionally withhold them.

The limitation creates an unusual testing paradox. Claude Code for web was isolated partly because it ran inside a microVM. That isolation prevented it from launching the different microVM that it had been asked to evaluate.

No meaningful Python or JavaScript attack workload reached smolvm during that attempt. The test produced no independent measurements for startup latency, memory enforcement, CPU saturation, file isolation, or termination behavior.

That missing evidence should shape any conclusion. It would be inaccurate to claim that the exercise validated smolvm as a secure execution service. It would also be inaccurate to treat the blocked launch as evidence against smolvm’s guest isolation.

Instead, the result identifies a deployment prerequisite. A team must run smolvm on a compatible physical host or a virtual machine that permits nested virtualization.

The official smolvm security model identifies KVM as the Linux backend. It also supports Apple’s Hypervisor framework and the Windows Hypervisor Platform on their respective operating systems.

That cross-platform design helps local development. It does not make smolvm runnable inside every existing agent sandbox, continuous integration worker, or serverless environment.

For the anthropic simon experiment, this is the first important reversal. The same isolation layer protecting the research agent also blocked the agent from testing a second isolation layer.

Anthropic Simon Exposed the Missing Control Plane

smolvm can supply a VM boundary, but the application around it must decide when code starts, what it receives, and when it dies.

The project describes smolvm as a command-line tool for isolated, portable Linux virtual machines. Each workload runs with its own guest kernel through libkrun, a virtual-machine monitor designed for lightweight workloads.

That architecture creates a stronger default boundary than an ordinary container. A conventional container normally shares the host kernel, even when namespaces hide processes, networking, and mounts. A smolvm guest receives a separate kernel behind a hypervisor boundary.

The distinction reduces direct exposure to the host kernel. It does not remove the need to distrust everything running inside the guest. smolvm’s documentation explicitly says operators should treat guest root as untrusted.

Its default network posture matches Willison’s goal. Network access is opt-in, so a machine launched without the networking option should not receive ordinary outbound connectivity. Host allowlists are available when an application needs narrowly scoped egress.

Filesystem exposure is also explicit. Host directories become visible only when the operator mounts them. That makes a staging-directory pattern possible for transformation jobs.

An execution service could copy designated inputs into a temporary directory. It could mount that directory read-only, provide a separate writable output location, and discard both after validating the results.

However, smolvm’s documented limitation is important. Its volume interface mounts directories, not individual files. A service promising access to “only designated files” must therefore build an isolated directory containing exactly those files.

The service must also defend that staging step. It should reject symbolic links, unusual device files, unexpected permissions, and paths that escape the intended directory. The VM boundary cannot correct a careless host-side file preparation process.

Memory configuration is available through the --mem option or a Smolfile, smolvm’s declarative machine configuration. The documented default is 8 GiB, with memory presented through an elastic virtio balloon.

Elastic allocation improves host utilization because the host does not immediately commit the entire configured amount. It should not be confused with admission control across many hostile jobs.

If a service launches numerous guests with optimistic allocations, aggregate demand can still overwhelm the host. The scheduler needs a separate capacity model covering memory, virtual CPUs, storage, and concurrent machine count.

CPU configuration has a similar distinction. Assigning one virtual CPU limits parallel execution within a guest. It does not automatically guarantee that the program receives only a fixed number of CPU-seconds.

A single-threaded infinite loop can consume its assigned virtual CPU forever. The hypervisor contains the loop, but an external supervisor must enforce a deadline and terminate the machine.

Production systems usually need both wall-clock and resource-based policies. A wall-clock timeout handles hangs, sleeping processes, and deadlocked programs. CPU accounting detects workloads that burn compute without making progress.

The supervisor must remain outside the guest. Code running inside the machine should not control the timer, termination signal, or final cleanup decision. Otherwise, the workload can attempt to disable its own guardrail.

This is why the phrase “sandbox for untrusted code” can hide two separate products. One is the isolation engine. The other is the control plane that safely schedules and supervises that engine.

The anthropic simon test was aimed at the complete product behavior. smolvm’s public interface mainly provides the isolation engine and low-level configuration required to build it.

A MicroVM Changes the Boundary, Not the Threat Model

Hardware virtualization improves containment, but every capability deliberately forwarded into the guest becomes part of the attack surface.

smolvm uses libkrun VMM to launch lightweight virtual machines. The guest receives its own kernel, while the host retains control over the virtual hardware and exposed devices.

This design addresses a central concern with containers. Containers isolate workloads using kernel features, but hostile processes still interact with the same host kernel through permitted system calls. A kernel vulnerability can therefore threaten the container boundary.

MicroVM systems move that boundary outward. The hostile code first encounters a guest kernel and virtual devices. Reaching the host generally requires crossing the virtual-machine monitor or hypervisor boundary.

AWS developed Firecracker microVMs around a similar principle for serverless workloads. Firecracker combines KVM virtualization with a deliberately reduced device model, limiting unnecessary emulated hardware.

smolvm is not simply a Firecracker wrapper. Its current documentation describes libkrun backends across macOS, Linux, and Windows. Still, both approaches place each workload behind a separate guest kernel.

That separation is relevant when an AI system writes code autonomously. Generated code can contain accidental destructive behavior, dependency attacks, credential probes, or deliberate payloads copied from untrusted data.

A data-transformation feature faces the same risk even without AI. A user could submit Python that scans the filesystem, forks repeatedly, allocates memory until failure, or attempts outbound connections.

JavaScript is not automatically safer. Node.js programs can read files, start subprocesses, open sockets, load native extensions, and exhaust memory when those capabilities remain available.

Language-level restrictions alone often become fragile because standard libraries expose broad functionality. Transitive dependencies can also introduce native code or unexpected access paths.

A full Linux guest lets developers run ordinary Python and Node.js packages without rewriting them for a specialized runtime. That compatibility is one reason microVMs remain attractive.

The tradeoff is a larger guest environment. The service must supply a kernel, runtime image, libraries, and virtual devices. Each maintained component affects patching, reproducibility, and the trusted computing base.

smolvm’s documentation names the host operating system, hypervisor backend, libkrun, smolvm, and invoking host account as trusted components. A compromise in those layers can weaken the promised boundary.

The documentation also warns about explicit capability forwarding. A mounted directory exposes its contents. Enabling networking expands reachable services. Forwarding an SSH agent lets guest processes request signatures while the socket remains available.

Those are sensible features for development machines. They should normally remain disabled in a service running anonymous or adversarial submissions.

GPU access needs even more caution. smolvm supports interfaces that involve shared host GPU resources or host-side processes. Its documentation says CUDA remoting should not be treated as hardened multi-tenant GPU isolation.

That limitation does not affect a simple Python data conversion job. It illustrates the broader rule: convenience features can cross the clean guest boundary that makes the basic architecture attractive.

For hostile workloads, the safest profile is intentionally boring. Use no network, no forwarded credentials, no host services, no GPU, minimal read-only inputs, and a disposable output area.

The VM should be destroyed after one job. Reusing a machine risks carrying altered files, processes, caches, or hidden state into the next user’s execution.

Portable images can help establish consistent runtimes. smolvm uses OCI images, based on the OCI image format, so operators can prepare Python or Node.js environments using a familiar packaging standard.

Image compatibility does not establish image trust. A production service still needs pinned digests, controlled registries, vulnerability handling, and a process for rebuilding runtimes after security updates.

Resource Limits Need More Than CPU and Memory Flags

The hardest “while true” defense is not isolation, but reliable termination under every failure mode.

A memory setting gives the guest a ceiling for visible RAM. When a program exceeds that capacity, the guest kernel can invoke its out-of-memory behavior. That contains one form of resource abuse.

The host still needs to observe what happens next. The guest might kill only one process, become unresponsive, or spend substantial time reclaiming memory. The service cannot assume that every memory failure produces a clean result.

A strict runner should classify outcomes. Success, user exception, memory exhaustion, timeout, output overflow, internal sandbox failure, and host-capacity rejection are different events.

That classification matters to users and operators. A transformation script with invalid syntax should not look like an infrastructure outage. A machine that fails to boot should not consume a user’s retry allowance.

CPU limits require several layers. The guest can receive a restricted virtual CPU count. Host controls such as cgroups can then regulate the VMM process relative to other workloads.

A deadline supervisor should terminate the entire VM after the allowed interval. Killing only the top-level Python or Node.js process is insufficient because the program can create children or background processes.

Termination must also have escalation. The supervisor can request graceful shutdown first, then stop the VMM process if the guest fails to respond. It should verify that related processes and temporary resources disappeared.

Output is another resource. A program can print indefinitely, create huge result files, or generate deeply nested data that consumes parser memory after execution ends.

The service needs byte limits for standard output, standard error, and generated files. It should stream or truncate logs without buffering unlimited content in application memory.

Storage quotas should apply to the guest’s writable layer and every exported output directory. Otherwise, a tiny input can produce enough data to fill the host filesystem.

Process count matters too. A fork bomb creates processes faster than a human operator can react. The guest kernel needs process limits, while the host should constrain the VMM and its supporting processes.

A hostile program can also exploit time without saturating a CPU. It might sleep forever, wait for absent input, or create a deadlock. That is why wall-clock deadlines remain mandatory.

Time should be measured by the external control plane. A guest can modify its own clock or interfere with internal watchdog processes. The host’s monotonic timer provides a more reliable source.

File export must happen only after execution ends. The host should inspect file types, sizes, paths, and counts before moving results into durable storage.

For common data transformations, a narrower output contract can reduce risk. The runner might accept one JSON document, one CSV file, or a bounded archive instead of an arbitrary directory tree.

A service should also limit input complexity before launching the machine. Compressed archives can expand far beyond their uploaded size, while malicious formats can target parsers outside the guest.

The secure sequence therefore starts before smolvm. Validate and stage inputs, create a fresh machine, enforce runtime limits, stop the machine, inspect outputs, then destroy temporary state.

Observability belongs outside the guest as well. Operators need machine identifiers, image digests, start and stop times, exit classifications, resource peaks, and cleanup status.

Those records should avoid storing sensitive user data by default. Logs can become another leakage channel when scripts print input records, credentials, or proprietary content.

None of these requirements negate smolvm’s value. They define the surrounding work needed to turn its low-level primitives into a dependable service.

Docker, WebAssembly, and Hosted Sandboxes Still Compete

smolvm occupies a useful middle position, offering normal Linux compatibility with stronger separation than a shared-kernel container.

Docker remains the easiest starting point for many engineering teams. Images, registries, build tools, and orchestration systems already support container workflows at scale.

Containers can apply namespaces, capabilities, seccomp filters, read-only filesystems, and cgroup limits. Those controls can be appropriate when workloads are trusted or only moderately risky.

The shared kernel remains the central concern for fully hostile code. An escape vulnerability in the host kernel or container runtime can expose other workloads and host data.

smolvm changes that exposure by assigning a separate guest kernel to each machine. It also accepts OCI images, reducing some migration friction for teams with existing Python or Node.js environments.

However, container platforms have mature scheduling and policy layers. smolvm’s security documentation states that the standalone tool is not itself a hardened multi-user control plane.

A team replacing containers with smolvm must avoid losing operational safeguards during the move. Stronger isolation beneath a weaker scheduler can still produce an unreliable service.

WebAssembly follows another route. A WebAssembly runtime starts with a constrained capability model, then explicitly grants functions such as file or network access.

That approach can create a smaller interface for compact transformation workloads. It also supports rapid startup and precise embedding in an application.

Compatibility is the tradeoff. Standard Python and Node.js packages may expect Linux system calls, native extensions, subprocesses, or runtime behaviors unavailable in a restricted WebAssembly environment.

A team controlling the transformation language might accept those constraints. A service promising broad Python and JavaScript compatibility will encounter them quickly.

Hosted code sandboxes offer a third path. Vendors package machine lifecycle, timeouts, networking policy, storage, and APIs into managed services.

That can shorten implementation time. It also transfers sensitive code and data to another operator, introduces service dependencies, and limits control over the underlying isolation design.

Self-hosting smolvm keeps the runtime under the buyer’s administration. It also makes the buyer responsible for host hardening, security updates, capacity planning, monitoring, and incident response.

The choice should follow the workload rather than fashion. A constrained expression evaluator does not need a complete Linux guest. A complex Python package with native dependencies probably does.

For one-shot transformations, microVM startup must remain small relative to job duration. smolvm says packed workloads can boot in under 200 milliseconds, but independent measurements should cover the buyer’s exact hosts and images.

Benchmarks should include cold image retrieval, machine creation, runtime startup, input staging, execution, output validation, and destruction. Measuring only guest boot time understates user-visible latency.

Teams should also test density. One fast guest says little about a host running hundreds of simultaneous submissions under memory pressure.

The competitive question is therefore broader than isolation strength. It includes compatibility, startup behavior, scheduling maturity, operational burden, and the consequences of a successful escape.

smolvm deserves evaluation because it combines familiar Linux workloads with a VM boundary. The anthropic simon attempt shows that such evaluation must happen on infrastructure capable of exposing the required virtualization features.

Three Tests Will Decide Whether smolvm Is Ready

The next useful evidence must come from hostile workload tests, not another feature checklist.

The first signal is a reproducible test on a compatible bare-metal or nested-virtualization host. It should run both Python and JavaScript suites through the same external supervisor.

Those suites should include infinite loops, memory exhaustion, fork bombs, oversized output, filesystem probes, network probes, delayed child processes, and abnormal guest shutdowns. Every case needs an expected outcome.

A successful result would strengthen the case that smolvm can serve as the isolation engine for transformation jobs. Repeated cleanup failures or inconsistent termination would weaken it.

The second signal is explicit, documented lifecycle enforcement. A reference runner should show how to impose wall-clock deadlines, host-level CPU controls, memory ceilings, output quotas, and complete machine destruction.

Configuration flags are not enough. The test should verify behavior when the guest ignores shutdown requests, fills storage, and leaves descendant processes behind.

This signal would close the gap between smolvm’s VM primitives and the service Willison originally wanted to examine. Without it, every adopter must design the critical supervisor independently.

The third signal is security review under a declared threat model. The review should identify trusted host components, mounted-file behavior, network enforcement, image provenance, and multi-tenant assumptions.

smolvm’s existing documentation already makes useful disclosures. It says releases currently lack signatures and provenance attestations, although checksum verification is available when its checksum file can be downloaded.

That disclosure gives evaluators a concrete supply-chain question. A production operator needs a controlled method for acquiring, verifying, pinning, and updating the smolvm binary and guest images.

An assessment should also distinguish local single-user execution from hostile multi-tenancy. A developer running generated code on a laptop faces different consequences than a public service accepting anonymous submissions.

No sandbox can convert arbitrary code into a risk-free workload. The practical goal is layered containment, controlled capabilities, bounded resource consumption, and fast recovery when one layer fails.

The most promising deployment pattern uses smolvm as one layer within that system. A host service validates inputs, creates a disposable guest, withholds network access, enforces deadlines, checks outputs, and destroys the environment.

For teams building AI workflows, the lesson extends beyond code execution. Any system that lets a model act on local information needs explicit boundaries around what the model can read, write, and retain.

A searchable knowledge base can help engineers retain test results, threat models, and incident findings. It cannot replace runtime isolation, but it can make security decisions easier to audit.

The anthropic simon experiment should therefore be treated as an unfinished evaluation with a useful first finding. smolvm could not run inside the chosen Claude Code environment because the outer sandbox withheld virtualization access.

The next step is not to relax that outer sandbox. It is to repeat the evaluation on a dedicated compatible host with an external supervisor and a published adversarial test suite.

Would your service still stop every job, preserve only approved outputs, and clean up completely when the guest becomes hostile? If that answer has not been measured, the sandbox is not ready for user code.

Get started for free

A local first AI Assistant w/ Personal Knowledge Management

remio only supports Windows 10+ (x64) and M-Chip Macs currently.

Your AI Partner at Work
Get more done with remio

Plan. Create. Deliver.
All in one place.

bottom of page