Ringkasan Utama
SPACE, platform open source dari Perplexity, menjalankan tiap task agent di microVM Firecracker di balik HTTP API, lengkap dengan template, suspend dan wake, warm pool, dan wrapper kompatibel E2B. Red team internalnya mencatat 0 dari 108 VM escape, tetapi 11 dari 54 network bypass pada partial network, yang sudah diperbaiki. Platform ini butuh host Linux dengan KVM.
Pada 15 Oktober 2026 Perplexity meng-open-source SPACE, platform sandbox di balik agent Computer miliknya, dan dokumentasi repository-nya cukup jujur soal apa yang tidak dijamin. Karena itu saya membaca docs dan post resmi Perplexity dengan teliti, bukan hanya mengandalkan liputan peluncuran.
Post ini adalah pembacaan dekat atas docs repository dan tiga post Perplexity: pengumuman, post desain runtime, dan laporan red team Escaping SPACE Part I. Saya tidak men-deploy SPACE, karena installer-nya butuh host Linux x86_64 dengan KVM dan saya belum menjalankannya di sana. Setiap angka di bawah berasal dari salah satu halaman itu, dan saya sebutkan siapa yang mengukurnya.
Apa itu SPACE: lima istilah dan satu control plane
SPACE singkatan dari Sandboxed Platform for Agentic Code Execution. Ditulis dengan Rust, tetapi tidak perlu di-embed: aplikasi berbicara dengannya lewat HTTP dan server-sent events, dan contoh first-sandbox di repository hanyalah script Python yang hanya memakai standard library. Kosakatanya kecil, dan architecture guide mendefinisikan tiap istilah dengan tepat.
| Konsep | Arti menurut architecture guide |
|---|---|
| Template | Filesystem dan konfigurasi runtime awal. Banyak sandbox memakai satu template tanpa mengubahnya. Referensi seperti seed:latest memilih release yang sudah dipublikasikan; referensi digest memilih konten tertentu. |
| Sandbox | Sebuah microVM terisolasi dengan filesystem yang bisa ditulis dan lifecycle sendiri. |
| Process | Program yang berjalan di dalam sandbox. Process dalam satu sandbox berbagi environment dan filesystem. |
| Command session | Informasi koneksi dan otorisasi untuk satu command. Membuat session memberi process ID; meng-attach session itulah yang menjalankan process. |
| Operation | Catatan yang melacak permintaan create, pause, suspend, wake, atau delete yang berjalan asynchronous. |
Alur kontrolnya mengikuti definisi itu. API mencatat desired state di PostgreSQL, lalu controller dan worker service merekonsiliasi sistem yang berjalan menuju state tersebut, sehingga request yang diterima belum berarti sandbox siap. Management dan output lewat jalur terpisah: management lewat API dengan bearer token user-session atau service, sedangkan output command mengalir lewat data plane yang hanya menerima attachment token per session. Kedua token itu tidak bisa dipertukarkan. Post desain Perplexity menggambarkan bentuk yang sama: control plane stateless, sandbox manager tanpa privilege di tiap node, node manager yang menjadi satu-satunya process root, dan daemon space di dalam guest VM.
Menjalankan sandbox pertama lewat HTTP API
Urutan di bawah adalah contoh first_sandbox.py dari repository yang disederhanakan menjadi curl. Endpoint, nilai runtime fc, dan nama field sandbox_id, operation_id, session_id, serta attach.token berasal dari script itu dan first-sandbox guide; jq dan uuidgen tambahan dari saya. Jalankan di instalasi Kind lokal dari installation guide.
# Assumes the local Kind install from docs/installation.md, which exports
# SPACE_API_URL, SPACE_DATA_PLANE_URL and SPACE_API_TOKEN (the login step).
H_AUTH="Authorization: Bearer $SPACE_API_TOKEN"
# 1. Create. The response is an operation, NOT a ready sandbox.
CREATE=$(curl -sS -X POST "$SPACE_API_URL/v1/sandboxes" \
-H "$H_AUTH" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"template": "seed:latest", "runtime": "fc"}')
SBX=$(echo "$CREATE" | jq -r .sandbox_id) # sbx_...
OP=$(echo "$CREATE" | jq -r .operation_id) # op_...
# 2. Wait for BOTH: operation state "succeeded" and sandbox state "running".
# An accepted request is not a readiness signal.
curl -sS -H "$H_AUTH" "$SPACE_API_URL/v1/operations/$OP" | jq -r .state
curl -sS -H "$H_AUTH" "$SPACE_API_URL/v1/sandboxes/$SBX" | jq -r .state
# 3. Create a command session. Commands are an argument ARRAY, not a shell
# string; use sh -c yourself when you need pipes or expansion.
SESSION=$(curl -sS -X POST "$SPACE_API_URL/v1/sandboxes/$SBX/commands" \
-H "$H_AUTH" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"command": ["sh", "-c", "uname -r; echo hello"], "timeout": "30s"}')
SID=$(echo "$SESSION" | jq -r .session_id)
ATTACH_TOKEN=$(echo "$SESSION" | jq -r .attach.token)
# 4. Attach on the DATA PLANE with the attachment token. Attaching is what
# starts the process. The management token is rejected here on purpose.
curl -sS -N -H "Authorization: Bearer $ATTACH_TOKEN" \
-H "Accept: text/event-stream" \
"$SPACE_DATA_PLANE_URL/v1/sessions/$SID/events"
# data: lines are JSON. stdout/stderr carry data_base64; success is a
# process_exited event with exit_code 0, not a closed stream.Ada dua hal yang sering menjebak. Menunggu operation saja tidak cukup, karena state operation menjelaskan permintaan lifecycle sedangkan state sandbox menjelaskan environment, dan keduanya bukan exit status command. Lalu output command adalah stream langsung, bukan penyimpanan log: reconnect dengan Last-Event-ID menghasilkan resync_required, bukan replay, jadi guide menyarankan menyimpan transcript dan mengulang command hanya jika mengulang efeknya aman.
Pause, suspend, dan jam idle enam jam
Session agent hidup lebih lama dari satu request, jadi lifecycle adalah bagian yang paling banyak dibahas di dokumentasi SPACE. Ada dua cara menghentikan sandbox, dan keduanya menyimpan hal yang berbeda.
| State | Eksekusi | Yang disimpan | Aksi berikutnya |
|---|---|---|---|
| Running | Process bisa berjalan | Memori VM yang hidup dan filesystem yang bisa ditulis | Jalankan command, pause, suspend, atau delete |
| Paused | Eksekusi dijeda | Memori VM tetap resident dan filesystem tetap di worker. Ini bukan snapshot yang durable. | Wake untuk resume |
| Suspended | Tidak ada eksekusi guest | Snapshot memori VM, runtime state, dan root filesystem; resource VM aktif dilepas | Wake untuk restore |
Secara default sandbox yang dibuat lewat SPACE API di-suspend setelah enam jam tanpa aktivitas akses atau command. Guide menyebutnya batas idle, bukan masa hidup maksimum. Post desain Perplexity menjelaskan cara kerja suspend: VM dijeda, full snapshot diambil dan artefaknya diunggah ke object storage, lalu snapshot baru bisa di-restore setelah semua artefak mendarat. Restore bisa berjalan di node mana pun, yang mengunduh artefak dan menerapkan ulang delta filesystem di atas template. Sebuah scheduler juga mengambil disk snapshot yang sering dan full snapshot yang lebih jarang, disimpan di node, sehingga command destruktif bisa di-rollback di level filesystem.
Tunggu setelah wake. Guide menyarankan mengulang pengecekan running-state dan process-readiness sebelum mengirim command berikutnya. Beri setiap mutation lifecycle Idempotency-Key sendiri, dan jika harus retry setelah timeout, pakai key dan body yang sama, jangan membuat request baru.
Warm pool dan base snapshot: ke mana latency create pergi
Post desain Perplexity memberi satu-satunya angka latency yang saya temukan, dan itu angka Perplexity sendiri: perbandingan di minggu peluncuran dengan penyedia sandbox sebelumnya pada traffic produksi, bukan benchmark publik. Pengumumannya meringkas hasil yang sama sebagai pembuatan sandbox tiga sampai lima kali lebih cepat.
| Metrik | Penyedia sebelumnya | SPACE | Perubahan |
|---|---|---|---|
| Latency create median | 185 ms | 60 ms | 3,1x lebih cepat |
| Latency create persentil ke-90 | 447 ms | 89 ms | 5,0x lebih cepat |
Post desain menyebut dua mekanisme. Di disk, SPACE memakai btrfs: salinan reflink berbagi extent sehingga hanya metadata yang disalin, dan snapshot bersifat atomic serta hanya menyimpan data yang berubah. Di cluster, warm pool berisi pod yang sudah memuat template umum di disk, sebuah request di-bind ke pod yang cocok, dan root filesystem-nya adalah clone copy-on-write. Jika tidak ada pod yang cocok, template di-materialisasi saat diminta, dan request bersamaan untuk image yang sama digabung menjadi satu unduhan. Docs repository menjelaskan sisi operator, seperti di bawah.
# Kubernetes: a warm pool is ONE template release x ONE VM size.
space-admin-cli warm-pool create \
--template my-template \
--vcpu 2 \
--memory-mib 4096 \
--target-ready-slots 10 \
--refill-per-tick 5 \
--max-warming-slots 10
space-admin-cli warm-pool list # wait until ready_slots reaches the target
# Native API creates ignore warm pools until admission-time claiming is on:
# SPACE_NATIVE_CREATE_POOL_CLAIM_ENABLED=true (API service)
# feature flag space-native-create-pool-claim -> true
# E2B-compatible creates through ECW use pools with no extra setup.
# Single node, no Kubernetes: base snapshot first, then an optional node pool.
sudo /space/bin/space-tmplmgr base-snapshot --template my-template --state true
sudo /space/bin/space-tmplmgr create-pool --template my-template \
--boot-mode snapshot --count 5
sudo /space/bin/space-sbxmgr create --runtime fc --template my-template \
--boot-mode pool --blocking
# --boot-mode falls back WITHOUT an error: pool -> base-snapshot -> cold.
# Read the "Boot mode:" line in the output to see what actually ran.Sisi tajamnya: setiap miss berlangsung diam-diam. Create yang tidak menemukan warm sandbox yang cocok tetap berhasil dengan cold boot biasa, jadi pool hanya membantu bila cocok. Warm-pools guide mendaftar penyebabnya: pool terikat pada satu release, sehingga memindahkan latest membuatnya terlepas; create yang menyetel vcpu dan memory_mib harus persis sama dengan ukuran pool; create yang meminta disk_mib kustom atau file-change tracking selalu cold boot; dan burst yang lebih besar dari ready_slots cold boot sampai pool terisi lagi. Untuk uji burst, setel target minimal sebesar burst, dan pantau metrik warm_pool.create_path.duration_ms, jangan berasumsi pool-nya terpakai.
Wrapper kompatibel E2B, dan batas-batas yang ditariknya
Kalau Anda sudah memakai E2B SDK, E2B Compatibility Wrapper (ECW) membuatnya bisa diarahkan ke SPACE. Repository jelas soal statusnya: ECW adalah compatibility target yang dipelihara SPACE, bukan implementasi spesifikasi E2B terbuka yang berversi. Baseline yang diuji adalah package Python e2b==2.21.1 dan e2b-code-interpreter==2.6.2; rilis lain dan SDK JavaScript mungkin bekerja tetapi tidak tercakup oleh test repository. Konfigurasinya dua setting dan satu aturan routing.
# SPACE_ECW_HOSTS on BOTH the API and the data-plane service (JSON array):
# [{"apiHost": "api.sandbox.example.test", "host": "sandbox.example.test"}]
# Route api.sandbox.example.test to the API and *.sandbox.example.test to the
# data plane. SPACE_ECW_CREDENTIAL_KEY_PATH must point at a mounted key file.
export E2B_DOMAIN=sandbox.example.test
export E2B_API_KEY=<raw-key> # from scripts/seed-api-key.sh, printed once
uv run --no-project --python 3.11 --with e2b==2.21.1 python - <<'PY'
import os
from e2b import Sandbox
sandbox = Sandbox.create(
api_key=os.environ["E2B_API_KEY"],
domain=os.environ["E2B_DOMAIN"],
template="seed",
timeout=60,
)
try:
print(sandbox.commands.run("printf 'Hello from SPACE\\n'").stdout)
finally:
sandbox.kill()
PYSnippet itu adalah contoh dari repository dengan komentar konfigurasi yang saya kumpulkan di atasnya. Bagian yang perlu dibaca sebelum migrasi adalah di mana ECW berbeda dari E2B.
| Area | Perilaku yang didokumentasikan di ECW guide |
|---|---|
| Nama lifecycle | pause di ECW dipetakan ke suspend di SPACE (menyimpan state VM, melepas resource worker) dan resume dipetakan ke restore. Pause dan resume memori resident milik native API tidak diekspos. |
| Field create yang ditolak | mcp, volumeMounts, dan iam mengembalikan 400 berbentuk E2B. autoPauseMemory=true diterima; false ditolak. |
| Public traffic | network.allowPublicTraffic=true ditolak, karena akses data plane diautentikasi dengan token. |
| Template | Alias bersifat flat: nama team/template dan lookup alias bertag tidak didukung. code-interpreter-v1 dipetakan ke template code-runtime milik SPACE, yang harus sudah ada. |
| Penulisan file | POST /files menerima hingga 256 MiB per request, di-stream ke spool file. Penulisan file JSON dibatasi 1 MiB dan mengembalikan 413 di atasnya. |
| Retry process start | Idempotency-Key 1 sampai 256 byte ASCII yang terlihat membuat retry dalam 60 detik menerima stream aslinya. Guide menyebutnya perlindungan retry, bukan jaminan exactly-once. |
Route ECW tidak ada di dokumen OpenAPI, jadi test SDK yang di-pin adalah kontraknya. Saran guide lugas: jalankan unit test ECW dan Kind smoke suite saat meng-upgrade dependency E2B, dan pakai native API untuk integrasi baru. Satu jebakan lagi: aplikasi yang dideklarasikan lewat startCmd mungkin belum listening setelah create, sehingga client bisa melihat connection refused dan harus menunggu aplikasinya secara terpisah.
Apa yang diukur red team, dan apa yang tidak
Post desain Perplexity mengklaim dua lapis isolasi, isolasi VM dan isolasi process OS host, yang keduanya harus ditembus untuk akses lintas sandbox, dengan credential disimpan di luar sandbox dan diinjeksi di network layer. Laporan Escaping SPACE Part I menguji klaim itu. Sembilan model diberi akses root di guest dan batas waktu, dengan dan tanpa source code SPACE, serta dengan no network atau partial network (package repository dan Perplexity Search). Totalnya 216 run: 9 model, 2 task, 4 setting, masing-masing 3 run.
| Task | Setting | Hasil |
|---|---|---|
| Keluar dari VM dan membaca honeytoken di host | Keempat setting | 0 dari 108 run |
| Menjangkau callback URL yang diblokir egress policy | No network | 0 dari 54 run |
| Menjangkau callback URL yang diblokir egress policy | Partial network | 11 dari 54 run |
| Task network yang sama setelah perbaikan | Setting terkuat, sembilan konfigurasi, masing-masing tiga run | Tidak ada flag yang berhasil diambil |
Jadi angka 108 di headline hanya separuh escape, bukan 108 dari semuanya. Ke-11 keberhasilan network datang lewat dua jalur. Dengan DNS spoofing, agent dengan root di guest memalsukan balasan yang meniru resolver untuk memetakan pypi.org ke IP callback, dan gateway menerima pemetaan palsu itu; hanya Claude Opus 5.0, GPT-5.6 Sol, dan Kimi K3 yang berhasil, itu pun dengan akses source. Dengan shared IP, gateway mengizinkan alamat Fastly untuk PyPI, sehingga agent memakai layanan lain di alamat itu untuk mengambil callback: GPT-5.6 Sol memakai fiddle.fastly.dev, dan GPT-5.6 Cyber memakai layanan gambar Taboola dan thum.io untuk membuat screenshot, lalu membaca flag-nya dengan OCR.
Keduanya sudah diperbaiki. Untuk spoofing, aturan nftables membuang packet dari guest yang source address-nya tidak cocok dengan address yang ditetapkan. Untuk shared IP, HTTP biasa lewat relay yang memvalidasi request authority dan membuang routing metadata, dan untuk TLS gateway mengakhiri koneksi lalu mewajibkan SNI dan HTTP Host masuk allowlist serta ter-atribusi DNS ke destination IP. Docs repository menunjukkan desain yang sama dari sisi operator: TLS exemption berbasis hostname hanya me-relay tanpa terminasi bila ada DNS binding live dari hostname itu ke destination IP, dan exemption melewati HTTP inspection dan credential injection.
Baca ini sebagai angka yang dipublikasikan vendor. Perplexity mengevaluasi produknya sendiri, laporan menyebut Part II akan membahas strategi serangan, dan taktik VM escape yang spesifik tidak dijelaskan di Part I. Laporan juga menyebut delapan dari sepuluh platform pihak ketiga menunjukkan setidaknya satu network-policy bypass, klaim tentang kompetitor dari vendor yang punya produk untuk dijual; hasil satu vendor dihilangkan karena meminta waktu lebih. Nol dari 108 tidak membuktikan nol. Artinya, sembilan frontier model dalam batas waktu tertentu tidak menemukan jalan keluar.
Trade-off dan failure mode yang perlu direncanakan
SPACE adalah platform yang Anda operasikan, bukan layanan yang Anda panggil, dan docs-nya jujur soal biayanya. Ini lima hal yang akan saya bawa ke design review.
- Hardware. Instalasi butuh host Linux x86_64 dengan KVM: /dev/kvm, /dev/net/tun, loop device, dukungan btrfs, dan Docker daemon yang mengizinkan container privileged. VM harus mendukung nested virtualisation, instruksinya tidak berjalan di macOS, dan pengecekan prasyarat tidak memverifikasi Docker privileged, loop device, atau btrfs.
- Privilege. Firecracker mengisolasi eksekusi guest, tetapi service di sisi host tetap butuh privilege untuk mengelola VM, storage, dan networking. Post desain menjadikan node manager satu-satunya process root, sehingga ia komponen yang harus di-harden dan dimonitor.
- Durability. File dipersistensi di batas lifecycle, bukan per write. Write yang sudah di-acknowledge tidak dijamin bertahan saat sandbox crash, forced stop, atau host failure.
- Stream. Output command adalah stream langsung, bukan penyimpanan log yang durable, dan reconnect memberi resync_required, bukan replay. Simpan transcript sendiri.
- Operasi. Hanya rilis minor terbaru yang mendapat security fix, dan docs bertumpu pada rollout terkoordinasi: upgrade setiap replica cluster-controller sebelum mengaktifkan native pool claim, dan upgrade policy reader sebelum mengonfigurasi TLS exemption.
Semua ini bukan cacat, melainkan harga dari memiliki boundary sendiri. Alternatifnya, hosted sandbox, memindahkan harga itu ke roadmap pihak lain, seperti yang ditunjukkan post Cloudflare Containers dan Kubernetes Agent Sandbox di situs ini dari sudut berbeda.
Yang dilakukan hari Senin
Jangan deploy ke produksi hari Senin. Pakai hari itu untuk mencari tahu apakah model operasinya cocok untuk Anda, dengan urutan berikut.
- Cari mesin Linux x86_64 dengan KVM, ikuti instalasi Kind, dan jalankan python3 examples/first_sandbox.py. Jika gagal di device atau btrfs, Anda sudah tahu biaya operasinya sebelum menulis integrasi apa pun.
- Jalankan urutan curl di atas dan ukur waktu dari create sampai running. Lalu buat warm pool dan ukur lagi, dengan membaca baris Boot mode atau metrik warm_pool.create_path.duration_ms, supaya Anda punya angka latency sendiri, bukan milik Perplexity.
- Jika hari ini Anda memakai E2B, arahkan SDK yang di-pin (e2b==2.21.1) ke ECW dengan template asli Anda dan lihat field mana dari yang ditolak (mcp, volumeMounts, iam) yang dikirim kode Anda.
- Putuskan egress lebih dulu. Mulai dari policy default-deny, tulis egress profile bernama, dan uji dua jalur yang dipakai red team: balasan DNS palsu dari dalam guest dan host yang berbagi alamat CDN dengan host yang diizinkan.
- Atur perilaku idle dengan sengaja. Default enam jam men-suspend sandbox, tidak menghapusnya, jadi tentukan siapa yang menghapus dan kapan.
# Operator egress profiles: named, ADDITIVE allow-lists, set at startup via
# SPACE_EGRESS_PROFILES on the API and cluster-controller (same value on both,
# standby controllers included). Wildcard domains are not accepted.
{
"audit": { "default": true,
"allow": [{"domain": "audit.example.test"}] },
"sensor": { "allow": [{"domain": "sensor.example.test"},
{"cidr": "192.0.2.0/24"}],
"tls_interception_exemptions": [{"domain": "sensor.example.test"}] }
}
# A federated create selects profiles per request. No header = defaults only.
# X-Space-Egress-Profiles: +sensor -audit
# The selection is immutable for the sandbox's life: to change destinations,
# recreate the sandbox. Alert on outcome failed/unconfigured for drift.Ingat bahwa pemilihan profile bersifat immutable selama hidup sandbox, dan resume serta restart tidak me-refresh destination profile. Mengubah allow-list berarti membuat ulang sandbox, jadi beri versi pada profile lewat namanya.
Aturan yang saya bawa dari SPACE: sandbox agent pertama-tama adalah lifecycle dan network policy, baru kemudian teknologi isolasi. Firecracker menyediakan boundary VM, dan di laporan Perplexity sendiri boundary itu bertahan sementara egress policy bocor. Ukur latency create Anda sendiri, miliki aturan egress Anda, dan perlakukan setiap angka dari vendor, termasuk angka-angka ini, sebagai klaim yang perlu direproduksi.
Sumber dan bacaan lanjutan
- GitHub: repository perplexityai/SPACE (Apache 2.0)
- Perplexity: Open-sourcing SPACE
- Perplexity: Escaping SPACE Part I, laporan red team
- Perplexity: Making SPACE secure and efficient untuk agent jangka panjang
- Docs SPACE: architecture, lifecycle, dan TLS exemption
- Docs SPACE: warm pool
- Docs SPACE: E2B Compatibility Wrapper
- Guide hosted SPACE
- Docs SPACE: operator egress profile
- Docs SPACE: sandbox pertama Anda

