Isolation, Networking, and Credentials
Each machine has its own Linux kernel and a hardware-virtualized boundary. The boundary limits direct access to the host, while configured mounts, sockets, ports, network routes, and credentials deliberately grant capabilities across it.
Host isolation
A guest can access only the host resources made available to it. Review every host directory mount and forwarded socket before running untrusted code. A mounted directory exposes its contents with provided permissions.
The VM boundary does not make a deliberately shared host resource safe. Treat access to a Docker socket, SSH agent, source directory, or other host service as a security decision.
Confining the VMM on Linux
The guest kernel boundary protects the host from the workload. A second boundary protects the host from the process that runs the machine, in case a guest ever escapes into it. On Linux the VMM process can be confined two ways, both applied before it loads the hypervisor library and enters the guest run loop:
SMOLVM_SECCOMPrestricts it to a syscall allowlist.enforcekills the process on a disallowed syscall,auditlogs without killing, andoffdisables it. Enforce fails closed: a filter that cannot be installed stops the boot rather than running unconfined. Available on Linux on x86_64 and arm64.SMOLVM_LANDLOCKrestricts its view of the filesystem to that machine’s own rootfs, disks, and devices, denying the rest of the host.enforceoroff. Linux only.
Which default applies depends on how the machine is started:
| Started by | Default |
|---|---|
The SDK (smolmachines for Node or Python) | Both enforce, on Linux |
smolvm serve | Both enforce, changeable with --seccomp and --landlock |
| The boot helper invoked directly | Off unless set |
An explicitly set variable always wins, so SMOLVM_SECCOMP=off remains the escape hatch for a workload the allowlist does not cover. On macOS both are ignored, so setting them there changes nothing.
Networking
Local smolvm guest networking is off by default, and a machine usually does not need it for its image: machine create fetches a registry image on the host, and an ephemeral run starts from a shared seed unless seeding is turned off, as the CLI reference describes. Beyond the image, enable guest networking only when the workload must resolve DNS, call an external service, or accept published traffic. A networked machine resolves names through the host’s own resolver, so a VPN or corporate network that only answers DNS from its own resolver works without extra configuration; pass --dns <IP> to point the guest somewhere else, and --dns-option to add resolver options such as timeout:1. A cloud machine created without a network block gets open outbound access by default; set network explicitly when egress policy matters.
Egress can be restricted with hostname and CIDR allowlists. A platform policy also blocks selected sensitive address ranges. To keep the public internet open while closing everything private, pass --block-private: it blocks the LAN, internal and link-local ranges, cloud metadata, carrier-grade NAT and the host’s loopback. --allow-private CIDR reopens one private range under it, such as an internal registry, and cloud metadata stays blocked whatever it names. In a Smolfile these are block_private and allow_private under [network]. To refuse a range outright, pass --deny-cidr CIDR (Smolfile deny_cidrs under [network]): a deny is checked before any allow, so it wins over every allow list, and it implies --net.
Behind a corporate proxy or a TLS-inspecting firewall, two flags carry the host’s setup into a machine. --use-host-proxy passes the host’s HTTPS_PROXY, HTTP_PROXY, ALL_PROXY and NO_PROXY, or on macOS the system proxy, into the workload, rewriting a proxy on the host’s loopback to an address the guest can reach; the run is refused when nothing answers there. --trust-host-certs mounts the certificates the host trusts at /etc/smolvm-host-trust/ca-bundle.pem, read-only, for image pulls and the workload, and points SSL_CERT_FILE, NODE_EXTRA_CA_CERTS, REQUESTS_CA_BUNDLE and similar variables at it. Set SMOLVM_HOST_CA_BUNDLE to a PEM file when the host’s trust store is not the system default.
The image pull inside the machine uses --proxy and --no-proxy, or else the host’s HTTPS_PROXY, HTTP_PROXY, ALL_PROXY and NO_PROXY. A proxy on the host’s loopback is rewritten to the host’s outbound address, so it must listen beyond loopback; when it does not, the pull is refused up front with what to change.
Published ports and outbound access are separate choices. Grant only the routes and ports a workload needs.
A workload that builds its own network interface, such as a VPN client running
in kernel mode, needs the guest’s tunnel device. An image workload gets /dev/net/tun inside its container by default, because the microVM is the
isolation boundary and the workload runs VM-grade. Adding --unprivileged moves
the workload to a reduced device view that does not include it, so a tunnel
client and --unprivileged are mutually exclusive.
Secrets and SSH keys
Secret injection resolves a host environment variable, file, or keychain item and places the value inside the guest. --secret-keychain GUEST_VAR=SERVICE[/ACCOUNT] reads a macOS Keychain generic password, or a Linux Secret Service item, at each launch and never stores it. The value is plaintext from the guest’s perspective. Code running in the machine can read it.
SSH-agent forwarding follows a different model. Private keys remain in the host agent, and the guest receives access to an agent socket. The guest can request signatures for as long as that socket is available, so forwarding still grants the ability to use the corresponding key.
Credential substitution
A credential binding gives a workload the ability to use a secret at named hosts without ever holding it. The guest receives an opaque placeholder in the environment variable it expects; the host replaces the placeholder with the real value only on HTTPS requests to the binding’s allowed hosts, and only inside a request header unless the binding also allows a form body.
NOTION_API_KEY=secret_... smolvm machine create --name notes --image alpine:3.20 \
--credential [email protected]
smolvm machine start --name notes
smolvm machine exec --name notes -- sh -c \
'echo "$NOTION_API_KEY"; curl -s -H "Authorization: Bearer $NOTION_API_KEY" https://api.notion.com/v1/users/me' The first line of output is SMOL_PLACEHOLDER_NOTION_..., which is all the guest can read or exfiltrate. Notion receives the real key. The same placeholder sent to any other host travels as a literal string; a placeholder in a URL or query string is refused with a 403, and so is one in a request body unless the binding opts in to form bodies, below.
The value is read on the host for every request, from a [secrets] reference of the same variable name or, failing that, from the host environment variable of that name. Rotating it needs no restart. Each binding lists exact hosts or a wildcard such as *.example.com, which matches every subdomain but not example.com itself and needs a parent of at least two labels. When the machine also has allow_hosts every credential host must fall under it, a wildcard by its whole subtree, so widening the network never widens a credential. An OAuth refresh grant carries its token in the body: end the binding with :body and the placeholder is also substituted in an application/x-www-form-urlencoded body to the bound hosts. Branched machines inherit placeholders and keep working; each branch is resolved under its own name, so one branch can be cut off without touching the others.
Clients that honor SSL_CERT_FILE, CURL_CA_BUNDLE, REQUESTS_CA_BUNDLE, GIT_SSL_CAINFO, NODE_EXTRA_CA_CERTS or DENO_CERT work unmodified; the guest is given a bundle of the image’s own roots plus a per-machine CA at /run/smolvm/ca-bundle.pem. Substitution covers HTTPS on port 443 and a credential selects the virtio-net backend on its own.
Practical boundary
Asked what to worry about, the honest ranking is not the one people expect. A guest breaking out to the host is the rare case: it takes a bug in device emulation, and a machine here has its own kernel behind a small virtio device surface rather than an emulated PC.
What actually exposes a host is what you shared on purpose. A host mount is the guest’s write access to that directory. A published port is reachable from wherever the host is reachable. An allow list one entry wider than you meant is egress you did not intend. And the code running inside the machine is code you chose to run. Every one of those is off by default, so the exposure a machine has is the exposure you gave it.
For an untrusted workload:
- Keep networking disabled unless it is required
- Restrict egress to necessary hosts or networks
- Avoid mounting sensitive host paths
- Inject only credentials the workload may read
- Forward an SSH agent only when the workload may request signatures