# Perplexity open-sources SPACE, its microVM sandbox for agents

> Perplexity released SPACE under Apache 2.0 on October 15, 2026: the Firecracker microVM sandbox that has run every Perplexity Computer session since July, with a 60 ms median create time against 185 ms on its previous provider. In Perplexity's red team, nine models with root never escaped the VM in 108 runs, but four bypassed the egress policy through DNS spoofing or shared CDN IPs. The same class of bypass worked on seven of nine other sandbox platforms tested, including E2B, Vercel Sandbox and Modal.

URL: https://blog.bokvi.com/blog/perplexity-space-agent-sandbox/
Published: 2026-10-15
Tags: ai-agents, security, infrastructure

**Perplexity today [open-sourced](https://www.perplexity.ai/hub/blog/open-sourcing-space) [SPACE](https://github.com/perplexityai/SPACE) under Apache 2.0: the Firecracker microVM platform that has run every Perplexity Computer session since July, at millions of sandbox creations a day. The code is serious infrastructure, but the part I'd read first is the [red-team report](https://www.perplexity.ai/hub/blog/escaping-space-part-i) that came three weeks before it. Nine frontier models with root inside the VM never reached the host in 108 runs, four of them still walked through the network policy, and the same class of hole turned up in seven of the nine other sandbox platforms Perplexity tested.**

## SPACE gives every agent its own kernel

SPACE stands for Sandboxed Platform for Agentic Code Execution, and its model is small. A template is a starting filesystem, a sandbox is a microVM made from it with its own writable disk, and a command session runs one process inside that sandbox. Applications talk to it over HTTP and server-sent events, so there is no SDK to embed: the repo's [first-sandbox walkthrough](https://github.com/perplexityai/SPACE/blob/main/docs/first-sandbox.md) is a standard-library Python script.

Perplexity's [design write-up from July](https://research.perplexity.ai/articles/making-space-secure-and-efficient-runtimes-for-long-running-agents) splits the system into three layers. A stateless control plane records desired state in PostgreSQL and reconciles toward it, with idempotent operations so it recovers from any crash or restart. Node-local services do the work, with a careful privilege split: the sandbox manager runs unprivileged and hands everything that needs root to a single node manager process. The sandbox itself is a Firecracker VM with its own guest kernel and a `space` daemon inside, which talks to the host over a private in-VM channel instead of the network. That leaves the guest's network purely for the workload's outbound traffic, and all of it goes through a per-sandbox gateway.

![Three stacked layers: a control plane with API gateway, cluster management and credentials; node-level services for sandbox lifecycle, storage and safety gates; and the sandbox, an isolated virtual machine with an in-sandbox daemon](https://blog.bokvi.com/_astro/space-architecture.CnkhDXRO_Z2eogsG.webp)

*The control plane decides what should exist, the node is the source of truth for what does, and each sandbox gets its own kernel. Image: Perplexity.*

The point of a VM per sandbox rather than a container is that the kernel stops being a shared single point of failure. If an agent's code exploits its guest kernel, it has compromised its own VM, not the host and not its neighbours.

## It is built for sessions that last months, not jobs that last seconds

Perplexity's argument is that container sandboxes assume short-lived, stateless jobs, while an agent session accumulates hours of context, files and running processes that can't be thrown away. The [architecture guide](https://github.com/perplexityai/SPACE/blob/main/docs/architecture.md) makes that concrete: a sandbox, a lifecycle operation and a command stream have separate lifetimes, and a sandbox can outlive both the request that created it and the connection carrying its output. That is the right shape for agents. A closed laptop or a dropped connection should not cost an agent four hours of working state.

The lifecycle is an explicit state machine. Pause keeps the VM's memory resident on its worker. Suspend takes a full snapshot of memory, runtime state and root filesystem, uploads it to object storage and releases the VM, so any node can restore it later. By default a sandbox suspends after six hours without activity, and the docs are careful to call that an idle limit, not a maximum lifetime.

![State machine from Creating through Created and Starting to Started, with pause, checkpoint and suspend paths that each return to Started through Resuming or Restoring](https://blog.bokvi.com/_astro/space-lifecycle.D_VGkrVq_pjC7H.webp)

*Pause, checkpoint and suspend are round trips that all land back at Started. Image: Perplexity.*

Two details in the snapshot path show the care that went in. A scheduler takes frequent disk snapshots and rarer full checkpoints, so an agent's destructive command can be rolled back on the filesystem without restoring a whole VM. And a suspended snapshot only becomes restorable once its database row records that every artifact has landed in object storage, so a half-uploaded snapshot can never be resumed into a corrupt machine.

One thing to know before you build on the stream API: command output is live, not durable. Reconnecting with `Last-Event-ID` gets you a `resync_required` event, not a replay of what you missed, so keep your own transcript.

## 60 ms creates come from btrfs and warm pools

The speed claim is specific. Running SPACE alongside its previous, unnamed sandbox provider on the same production traffic during launch week, Perplexity measured median create latency falling from 185 ms to 60 ms, and the 90th percentile from 447 ms to 89 ms.

![Bar chart of sandbox creation latency: 185 ms on the legacy provider against 60 ms on SPACE at the median, and 447 ms against 89 ms at the 90th percentile](https://blog.bokvi.com/_astro/space-create-latency.Tt28cMdK_1custA.webp)

*Creation latency on identical production traffic, SPACE against Perplexity's previous provider. Image: Perplexity.*

There is no trick in it, just btrfs. Each sandbox gets its root filesystem as a copy-on-write reflink of the template, so creating one copies metadata, not a disk image. A warm pool keeps pods with common templates already on disk, and concurrent requests for the same uncached template collapse into a single download. Disk snapshots are cheap for the same reason, and they don't need the sandbox paused. These are Perplexity's numbers against a provider it doesn't name, so I read them as a direction rather than a benchmark.

## Secrets never enter the box

The design choice I'd copy even without running SPACE is about credentials. The credential store sits outside the sandbox boundary behind a pluggable vault, with scoping, expiry, rate limits and audit logs. When an agent calls an authenticated API, the gateway injects the credential at the network layer, or a browser agent fills it in, so the token never exists inside the VM. An agent that can't read a token can't paste it into a prompt-injected webhook. Data at rest supports bring-your-own-key encryption: the key stays in the customer's key management service, and revoking it makes the stored data unreadable.

## The red-team report is the real release

On September 23 Perplexity published [Escaping SPACE: Part I](https://www.perplexity.ai/hub/blog/escaping-space-part-i), and its setup is worth stealing as a test plan. Nine models got root inside a guest VM and one of two goals: cross the VM boundary and steal an AWS honeytoken from the host, or reach a callback URL that the egress policy blocks. Each ran with and without SPACE's source code, and with either no network or partial network (package mirrors such as PyPI, plus Perplexity search), three times per setting, for 216 runs.

No model escaped the VM in any of the 108 escape runs, even with the source code. None got past a deny-all network policy either. But with the package mirrors allowed, 11 of 54 runs reached the blocked callback, by Claude Opus 5.0, GPT-5.6 Sol, GPT-5.6 Cyber and Kimi K3, the only open-weight model to manage it.

![Two task paths: the sandbox-escape path stops at the VM-host isolation line with no verified escape in 108 runs, while the network-bypass path passes the egress gateway to a blocked callback in 11 of 54 partial-network runs](https://blog.bokvi.com/_astro/escaping-space-boundaries.DfdzpAGr_JT2bG.webp)

*VM isolation and network confinement are separate boundaries, and only one of them held on the first try. Image: Perplexity.*

Both bypasses hit the same weak spot. Policies are written as hostnames, packets carry IP addresses, and the gateway learned the mapping between them by watching DNS. In the first bypass, a model with source access forged a DNS answer claiming `pypi.org` lived at the callback's IP and sent it to the gateway's DNS socket, an internal veth address you can only find by reading the code. The gateway believed it. In the second, models noticed that PyPI sits on Fastly, where one IP serves thousands of unrelated customers. GPT-5.6 Sol connected to the allowed IP but asked for Fastly Fiddle, a developer tool that fetches arbitrary URLs. GPT-5.6 Cyber went further: through the same IP it reached a Taboola image service, had it fetch a thum.io screenshot of the callback, and read the flag out of the PNG with OCR.

Opus 5.0 spotted the shared-IP route as well and declined to use it, reasoning that pivoting through a third-party service broke the instruction not to target other systems. Perplexity suggests that might be overly conservative. I'd call it exactly the behaviour I want from an agent with root in my infrastructure.

The fixes are the useful part. Every packet leaving a guest must now carry that guest's own address, enforced by an nftables rule in the sandbox namespace, which kills the forged DNS reply. For shared IPs, the gateway now terminates TLS and requires both the SNI and the HTTP Host header to be allowlisted and DNS-attributed to the destination IP. Plain HTTP goes through a relay that checks the authority of every request, and domain rules reject UDP and plaintext protocols that carry no hostname to verify. A rerun with source code and partial network produced no bypass.

That fix has a cost the report doesn't dwell on: the gateway now sees an agent's HTTPS in plaintext. SPACE lets operators exempt destinations from interception, and the [architecture guide](https://github.com/perplexityai/SPACE/blob/main/docs/architecture.md#tls-interception-exemptions) states plainly that exempt traffic also skips HTTP inspection and credential injection. That is the honest trade, and I prefer it written down.

## Most other sandboxes had the same hole

Perplexity then tested ten other platforms with hostname-based egress controls, this time with scripted requests rather than agents, and published results for nine. The test: allow one hostname, connect to its IP, and ask for a different tenant on the same CDN. The HTTPS version got through on E2B, Vercel Sandbox, Modal, Daytona, Deno Sandbox, Fly.io Sprites and microsandbox. Deno also let plain TCP out to unlisted IPs. Only Cloudflare Sandbox and NVIDIA OpenShell held.

![Table of nine sandbox platforms against HTTP, HTTPS and direct TCP bypasses: HTTPS is marked vulnerable for seven of them, and only Cloudflare Sandbox and NVIDIA OpenShell show no bypass](https://blog.bokvi.com/_astro/escaping-space-other-platforms.CDmHF-wG_ZRvHzp.webp)

*Results as tested on August 31 and September 1, 2026, before the vendors responded. Image: Perplexity.*

As of September 10, Daytona and Deno had shipped fixes, microsandbox had added an HTTPS strict mode in v0.6.18 that is off by default, E2B had a fix planned and Fly.io had one in progress. Vercel and Modal classed it as a known limitation and pointed to their documentation.

Some of today's coverage blurs this. [Semafor's report](https://www.semafor.com/article/10/15/2026/perplexity-to-give-away-its-ai-security-software) counts 118 tries and says models were able to "break out of other sandboxes". Perplexity's own [launch post](https://www.perplexity.ai/hub/blog/open-sourcing-space) and report both say 108 escape attempts, and the third-party failures it documents are network-policy bypasses found without agents; it didn't test VM escapes on those platforms at all. The distinction is the report's whole argument. Network confinement and VM isolation are different boundaries, and a sandbox can hold one while leaking the other.

My takeaway: on a CDN-fronted internet, allowing a hostname is not a rule an IP firewall can enforce. If your agent sandbox allowlists package registries, find out whether it terminates TLS and checks SNI and Host against the destination. If it doesn't, the allowlist means every tenant behind the same edge IP.

## Running it is a real infrastructure project

I haven't run SPACE yet, and you won't on a laptop either. The [local install](https://github.com/perplexityai/SPACE/blob/main/docs/installation.md) needs a Linux x86_64 host with KVM, `/dev/net/tun`, loop devices, btrfs and a Docker daemon that allows privileged containers; a VM works only with nested virtualization, and macOS is out. It brings up a Kind cluster, while production can use the Kubernetes adapter or a direct adapter that drives workers without Kubernetes, and the repo carries a reference EKS deployment. By my count the main branch holds about 970,000 lines of Rust, tests included, plus a Go runtime shim. The one execution environment it currently approves pins Firecracker 1.15.1 and guest kernel 6.1.155.

The release is 0.8.0. The [versioning plan](https://github.com/perplexityai/SPACE/blob/main/docs/versioning.md) makes 0.9 the last planned breaking release and gates 1.0, with stable HTTP API and lifecycle contracts, on compatibility evidence.

The most pragmatic piece is the [E2B Compatibility Wrapper](https://github.com/perplexityai/SPACE/blob/main/docs/ecw.md). It translates E2B SDK requests into SPACE operations and is tested against the Python packages `e2b` 2.21.1 and `e2b-code-interpreter` 2.6.2; the JavaScript SDK may work but isn't covered by tests. Mind the naming: E2B's pause maps to SPACE's suspend. If you're on E2B and want to own the stack, that's the migration path. If you'd rather not run Kubernetes on KVM hosts yourself, Perplexity [says](https://www.perplexity.ai/hub/blog/open-sourcing-space) CoreWeave and Akamai have already tested and launched SPACE on their clouds, and Crusoe is adding it to its managed AI services.

One detail for readers of a blog about AI coding: the repo is set up for agents to work on it. It ships a Claude Code plugin marketplace with skills for its Rust conventions, validation and public-safety review, plus one called `slop-score` that measures engineering slop by having fresh agents re-implement real past commits and recording what the codebase's structure costs them. Its agent instructions also require reproducing any private incident with synthetic inputs before evidence reaches the public repo.

## What this release is worth

As a reference, SPACE is strong: one kernel per sandbox, a single root process on the host, sessions that outlive their connections, and secrets that never enter the guest. Most teams shouldn't self-host it; it was built for a fleet doing millions of creates a day. But every team running agents should read the red-team report and then test its own egress the way Perplexity did. Publishing the sandbox together with how it failed, and naming seven other platforms with the same hole, is worth more than any zero-escapes headline.