Security Model
agentOS is a sandbox: it runs untrusted code safely on behalf of a trusted caller. Every actor boots its own fully virtualized VM with a virtual filesystem, process table, socket table, pipes, PTYs, a permission policy, and managed language runtimes. Guest JavaScript executes in a V8 isolate, and every guest syscall is serviced by the kernel rather than the host. There are no host escapes: guest code cannot spawn a real host process, touch the real host filesystem, or open a real host network socket.
Deny by default
Section titled “Deny by default”No syscalls are bound to the system by default. Everything is denied until explicitly opted in.
- Network access is denied until you opt in with a
networkpermission. - Filesystem mounts expose nothing of the host until you configure them.
- Process spawning runs only kernel-managed guest processes, never host processes.
- All other host capabilities must be configured by the host before the VM can use them.
Other in-VM scopes (the virtual filesystem, child processes, process info, env) are enabled so that normal programs run, but they are mediated entirely by the kernel and never touch the host.
Trust model: three components
Section titled “Trust model: three components”Before judging whether something is a security bug, decide which side of the boundary it is on. agentOS has three components with very different trust levels.
Client (trusted)
Section titled “Client (trusted)”The party that configures and manages the VM: your application code, container, or serverless function.
- The client process and every value it sends are trusted: VM config, mount descriptors and their plugin configs (host directory paths, S3 endpoints and credentials, etc.), the permission policy, network allowlist, resource limits, env, and DNS overrides.
- Configuration is not an attack surface. A defect that requires the client to supply a malicious config, endpoint, credential, or policy is not a sandbox vulnerability: the client is configuring its own VM and already controls the host.
- The one thing from the client that is not trusted is the code/payload it asks to run, because that runs in the executor. How code reached the executor never makes it trusted.
You are responsible for hardening this side. See What you are responsible for.
Sidecar / kernel (trusted, the enforcement point)
Section titled “Sidecar / kernel (trusted, the enforcement point)”The trusted computing base. It brokers client requests and owns the kernel, VFS, mount/plugin registry, socket table, and permission policy. It is responsible for enforcing the boundary against the executor.
Executor (untrusted, the adversary)
Section titled “Executor (untrusted, the adversary)”V8 isolates or WASM running guest JS/Python/WASM plus any third-party, npm, or agent-generated code.
- Assume everything here is actively hostile.
- The executor reaches the outside world only through kernel-owned VFS, process, socket, pipe, PTY, permission, and DNS paths.
The security boundary
Section titled “The security boundary”The security boundary is sidecar ↔ executor. The runtime must stop guest code in the executor from:
- Escaping the kernel boundary (the real host filesystem, network, process table, or memory).
- Bypassing the applied permission policy, allowlist, or limits.
- Exhausting host resources beyond configured bounds.
- Reading another VM’s state.
Two corollaries that are easy to get wrong:
- Trusted policy, untrusted subject. The permission policy and limits are trusted input, but the guest executor is the subject they bind. “Guest bypasses an applied permission, egress rule, or resource cap” is in-scope and serious. Trusted = who sets the rule; untrusted = who is bound by it.
- Trusted mount, untrusted traffic. A host-backed mount (host directory, S3, etc.) comes from trusted config, so its existence, target, and credentials are not attack surface. But the guest drives I/O through it, so confining those guest operations to the mount root (symlink,
.., TOCTOU, and path-aliasing escapes) is in-scope.
In scope vs out of scope
Section titled “In scope vs out of scope”| In scope (sandbox escape) | Out of scope (not a sandbox bug) |
|---|---|
| Guest reaches the real host fs / net / process / memory | Client supplies a malicious config / endpoint / credential / policy |
| Guest bypasses an applied permission, egress rule, or limit | Hardening that only guards trusted client-provided configuration |
| Guest exhausts host resources past configured bounds | Wire-level authn/authz between mutually distrusting clients |
| Guest reads another VM’s state | VM-to-VM access via forged connection IDs (single-client transport) |
Guest escapes a host-backed mount root (symlink / .. / TOCTOU) | The existence or target of a configured mount |
Transport scope. The wire protocol is same-version lockstep and single-client over stdio (one trusted client per sidecar process). There is no second, mutually-distrusting client, so wire-level authn/authz between clients and VM-to-VM access via forged connection IDs are out of scope until a multi-client transport exists.
VM isolation
Section titled “VM isolation”Each agentOS actor runs in its own isolated VM.
- Sandboxed execution. All agent code runs inside a V8 isolate with WebAssembly. No code escapes the isolate boundary.
- Virtual filesystem. The VM has its own in-memory filesystem. Guest reads and writes never reach the real host filesystem. Agents cannot access host files unless explicitly mounted.
- Virtual network. The VM has no direct access to the host network. Outbound requests are proxied through the host with configurable controls.
- Process isolation. No host process is visible or accessible from inside the VM.
- Per-actor containment. Each actor is its own VM. Two actors share no filesystem, globals, module state, memory, or crash fate. The sidecar process that hosts those VMs may be shared by default as a performance optimization, but isolation is enforced at the VM level, not the host-process level.
Kernel-owned syscall paths
Section titled “Kernel-owned syscall paths”Every guest syscall is mediated by the kernel and checked against the runtime’s permission policy. Concretely, the kernel mediates:
- Filesystem. A virtual, in-memory filesystem. Guest reads and writes never reach the real host filesystem. Host data enters the VM only through the
files,mounts, ornodeModulesyou configure explicitly. See Filesystem. - Processes.
node:child_processspawns kernel-managed guest processes, never real host processes. Children can only run the commands the VM mounts (WASM-backedshand coreutils, V8-backednode). See Processes. - Network. Guest
fetch(),node:http, and raw sockets all flow through the kernel socket table. Guestfetch()runs through undici inside the isolate and then through the kernel socket table; it never opens a real host socket. See Networking. - DNS, pipes, and PTYs are likewise kernel-owned: no guest path reaches the host directly.
- Bindings. Registered bindings are the only sanctioned way to hand the guest a named host capability. The guest invokes a binding by name with JSON input, the call round-trips to the host handler, and only the handler’s return value comes back. The guest never receives the underlying host access.
What enters the VM
Section titled “What enters the VM”The host filesystem is never exposed to the guest by default. Host data crosses the boundary only through options you configure:
filesseed bytes into the virtual filesystem. The bytes are copied in; the host path is never exposed.mountsproject a host directory at a guest path, Docker-style. The guest sees only the mounted subtree, read through the VFS lazily, never the wider host filesystem. Mounts are read-only unless you opt out.nodeModulesproject a hostnode_modulesdirectory (read-only, lazily) at a guest path so guestimport/requireresolves real installed packages.
In every case the guest sees only the subtree you mount, and writes to read-only mounts are rejected.
Permissions
Section titled “Permissions”Permissions are the capability gate at the boundary. They merge over a secure default that denies the network and enables the filesystem, child processes, process info, and env. Because the merge is partial, you name only the scope you change.
// Grant network egress; everything else keeps the secure defaults.permissions: { network: "allow" }A scope can be "allow", "deny", or a { default, rules } policy that matches request patterns. Guest servers are reachable only over loopback inside the VM unless you exempt a port explicitly. See Permissions and Networking for the full policy shape.
Resource and timing limits
Section titled “Resource and timing limits”The VM bounds guest execution so runaway or hostile code cannot hang or exhaust the host:
- Timeouts and cancellation kill or cancel a run from the outside.
- Memory, CPU-time, and payload limits are enforced by the VM.
- Timing-side-channel mitigation. In the default mode, high-resolution clocks (
Date.now(),performance.now(),process.hrtime()) are frozen within a run andSharedArrayBufferis removed, to blunt timing side channels of the kind used in Spectre-style attacks.
See Security & Auth for resource limits, network control, and authentication setup.
What agentOS guarantees
Section titled “What agentOS guarantees”- Agent code cannot read or write host files outside configured mounts.
- Agent code cannot make network requests except through the host proxy.
- Agent code cannot access host environment variables or secrets.
- Each actor’s filesystem, sessions, and state are isolated from other actors.
- Resource limits (CPU, memory) are enforced at the VM level.
- A crash, resource exhaustion, or escape attempt is contained to a single VM; other VMs keep running, even when they share a sidecar process.
What you are responsible for
Section titled “What you are responsible for”The boundary protects the host from the guest. It does not harden your host process against everything else. The VM alone is not enough without a hardened host, and a hardened host alone does not protect against code that runs with full host access inside your own process.
- Hardening the host process and deployment environment. For internet-facing workloads that take untrusted input, run your host inside an already-hardened environment (for example AWS Lambda, Google Cloud Run, or a similar sandboxed platform).
- Validating authentication tokens in
onBeforeConnect. - Scoping permissions appropriately for your use case.
- Managing API keys and secrets on the host side (use the LLM gateway to avoid passing keys into the VM).
- Configuring resource limits and network controls to match your threat model.
- Choosing your blast radius: prefer a fresh VM per untrusted or high-risk task so an escape attempt cannot outlive a single VM.
Further reading
Section titled “Further reading”- Security configuration for resource limits, network control, and authentication setup
- Permissions for agent tool-use approval patterns
- agentOS vs Sandbox for when to escalate to a full sandbox