Environment probe · comparative analysis · rev 3
Four agent environments, each probed from the inside. Three are built to run untrusted code; the fourth only looks like it is. The clearest signal of intent in all four is not the toolchain but the egress policy.
Where the boundary sits, and how much sits above it.
| Dimension | chat | cowork | kimi | ai studio |
|---|---|---|---|---|
| Isolation model | Firecracker microVM | Firecracker microVM | containerd container (K8s pod) | gVisor (runsc) on Cloud Run |
| Kernel | own guest, 6.18.5 | own guest, 6.18.5 | shared host, 5.10.134 | user-space kernel, 4.19.0-gvisor |
| PID 1 | process_api (Rust) | process_api (Rust, vsock) | s6-svscan | /bin/bash ./start.sh |
| Root filesystem | ext4 | ext4 + 2× ro squashfs | overlayfs, 114+ layers | overlay (378 GB — a gVisor reporting artifact) |
| Base OS | Ubuntu 24.04.4 · 20260410 | Ubuntu 24.04.4 · same serial | Debian 12 on LifseaOS | Debian 12, largely unminimised |
| Instance marker | --wiggle-- | --remote_cowork-- | numeric instance ID | Cloud Run K_SERVICE / K_REVISION |
| Agent uid | root | root | root | root (nginx workers drop to nobody) |
Anthropic's public containment write-up describes claude.ai code execution as gVisor, while direct probing of the chat sandbox finds Firecracker. AI Studio is useful here precisely because it is unambiguously gVisor, and shows what that leaves behind: df /var/log returning Function not implemented, and a CPU model reported as unknown. Neither fingerprint appears in the chat sandbox.
That does not resolve the discrepancy — both may be true of different code paths — but it does establish what the gVisor case looks like from inside.
| Setting | chat | cowork | kimi | ai studio |
|---|---|---|---|---|
| init_on_free=1 | set | not set | not set | n/a — no guest kernel |
| nomodule | set | set | not set | n/a — modules impossible under gVisor |
| SELinux | n/a (VM) | n/a (VM) | selinux=0 | n/a |
| Kernel audit | n/a | n/a | audit=0 | n/a |
| Spectre IBRS | default | default | noibrs | host-managed |
| Syscall interception | hardware VT | hardware VT | none | full — gVisor's core mechanism |
| Loopback bypass | blocked | blocked | sshd on 0.0.0.0:22 | n/a — loopback is the architecture |
gVisor and Firecracker are different answers to the same question, and both are credible: one intercepts syscalls in user space, the other gives the guest its own kernel behind a hardware boundary. Kimi's shared host kernel with mitigations disabled is the outlier — not because containers are unsound, but because that particular flag set spends containment on performance.
Cowork figures from the 2026-07-24 probe. See §6 for week-over-week drift.
| Dimension | chat | cowork | kimi | ai studio |
|---|---|---|---|---|
| CPU | Xeon @ 2.80 GHz | Xeon @ 2.80 GHz | Xeon Platinum @ 2.50 GHz | masked (unknown) |
| Cores | 1 vCPU | 2 vCPU | 2 vCPU | 2 vCPU |
| RAM | 3.9 GB | 7.8 GB | 4.0 GB | 4.0 GB |
| Swap / GPU | none / none | none / none | none / none | none / none |
| Disk | 252 GB | 252 GB, 30 GB avail | 40 GB | 378 GB reported — see note |
| Python / Node | 3.12.3 / 22.22.2 | 3.11.15 / 22.22.2 | 3.12.12 / — | 3.10.12 / 22.23.1 |
| User-data transport | 4× rclone FUSE | local ext4 | FUSE portal | none — overlay only |
| Persistence | rclone cache non-determinism | ephemeral; durability via git | overlay ephemeral; backend unobservable | fully ephemeral, no mechanism exposed |
/, /dev, /dev/shm and /tmp all report 378 GB in the AI Studio probe. That is one synthesised number repeated across four overlay mounts — a gVisor filesystem-layer artifact, not a provisioned allowance. It is not comparable to chat and Cowork's 252 GB block device.
Same component class, four different intentions.
| Dimension | chat | cowork | kimi | ai studio |
|---|---|---|---|---|
| Mechanism | 403 intercept, x-deny-reason | TLS-terminating MITM + Anthropic CA | Bright Data residential proxy | none |
| Intent | restrict reach | restrict reach, across many toolchains | extend reach past anti-bot defences | no policy — reach is unconstrained |
| Exit IPs | Anthropic infra | Anthropic infra | rotating residential ISPs (TH, ID) | Google infra, direct |
| Metadata endpoint | not tested | hard-blocked | not reported | reachable — token extractable |
| Anti-detection | none | none | automation flags stripped, UA spoofed | none |
| Scope | all traffic | all traffic | browser only | all traffic, unfiltered |
| Ingress control | n/a | n/a | sshd, key-only | nginx + Lua token bridge — where the security work went |
Anthropic's proxies are a cage. They exist so the agent cannot reach things. Kimi's is a disguise — it exists so the agent can reach things that would otherwise block it, via residential exit IPs and stripped automation fingerprints. That design is internally coherent: exposing the pool to Chromium but not to Python stops arbitrary code from abusing the IP pool. It carries a third-party consent question, since traffic exits through real consumer connections.
AI Studio has neither, and that is the point of §4: it spent its budget somewhere else entirely.
Read the process tree before reading the findings.
PID 1 is a shell script that starts nginx, starts a Go control plane, waits for /health, and then blocks on tail -f /dev/null. Behind nginx sits a Vite dev server — the application being built. There is no tool dispatcher and no execution policy gate, because the product's job is to host a preview of your app and control who can load it, not to run adversarial code safely.
Nearly all of its security engineering is on ingress: every request to / passes an nginx Lua script that validates a token against aistudio.google.com, caches results in a shared dict, retries around token-minting replication lag, rejects javascript: return URLs, and carries a dedicated fallback for iOS Safari's cross-site cookie blocking. That is careful work. It is simply pointed at a different threat.
| Finding | As filed | Calibrated | Why |
|---|---|---|---|
| Metadata server reachable; OAuth token extractable | high | default · mitigated | Every Cloud Run container reaches 169.254.169.254; platform default, not an AI Studio choice. The control is IAM scoping, and the same session confirmed it holds — two API calls returned 403 and Cloud Resource Manager is SERVICE_DISABLED. |
| Model API key in plaintext environment | high | real, severity undetermined | Mechanism is genuine — any transitive npm dependency reads process.env, and egress is open. But severity depends on whether the key is per-applet disposable or shared platform, which the probe never established. |
DISABLE_AUTH_BRIDGE switches off ingress auth entirely |
not filed | highest-consequence control | Documented and warned in-file, intended for eval containers. Still the one variable whose misapplication turns an authenticated preview into an open one. It went unmentioned in the source audit. |
| Unrestricted egress | high | accurate fact, mis-framed | True and worth stating — but a preview host that cannot reach the internet cannot serve most applications. This belongs in the threat-model discussion, not the vulnerability list. |
AI Studio is still unsuitable for running untrusted third-party code. Root execution, open egress and secrets in the process environment compose badly, and that combination is real. The correction is to the framing: these are properties of a preview host being used as an execution sandbox, not defects in an execution sandbox.
Four product classes, not four sizes of one thing.
| Dimension | chat | cowork | kimi | ai studio |
|---|---|---|---|---|
| Runtime on top | 4-tool interface | Claude Code CLI 2.1.218 | s6 stack + Jupyter kernel | nginx + Go control plane + Vite |
| Interaction model | one-shot tool execution | agent: MCP, hooks, sub-agents, scheduled tasks | remote desktop: Xvnc + Chromium + pyautogui | app preview served through an auth bridge |
| Browser | Playwright, headless | Playwright + Chrome automation | Chromium 149 on a real X display | none — the browser is the user's |
| Databases | none | Redis + Postgres 16.13, in-box | not reported | none |
| Containers | absent | present, daemon off, Hub blocked | not reported | absent |
| Systems toolchain | gcc, Java | Rust, Go, strace, lsof | minimal image | none — JS/TS and Python only |
| Reach to user's machine | none | remote-devices bridge | SSH in, key-only | none |
| Git posture | a capability | central — commit signing, stop hooks | not reported | not a concern of the product |
chat — hardened ephemeral scratchpad. Reason, generate documents, run short code.
cowork — git-native software-engineering agent. Docker tooling, proxy trust bundle and signing hooks all exist to run a general dev toolchain under one policy gate.
kimi — multimodal desktop agent. It gives the model a screen and a mouse rather than a CLI; the browser, VNC and residential proxy all follow from that.
ai studio — application preview host. It gives the model a web server and gives the user an authenticated URL.
Cowork and Kimi are closer in ambition to each other than either is to chat, reached by opposite routes: Cowork hands the agent a developer's terminal, Kimi hands it a user's desktop. AI Studio hands it neither.
2026-07-15 → 2026-07-24. Only fields that moved.
| Field | 07-15 | 07-24 | |
|---|---|---|---|
| claude_cli | 2.1.210 | → | 2.1.218 |
| agent | claude-code_2-1-210_agent | → | claude-code_2-1-218_agent |
| runner | staging-a54e7c22b | → | release-1186d93b9-ext |
| cpu | Xeon @ 2.10 GHz | → | Xeon @ 2.80 GHz |
| https_proxy | 127.0.0.1:45919 | → | 127.0.0.1:39185 |
staging → release. The most consequential field. The 07-15 findings were taken against a pre-release runner and should not be assumed to describe the shipping environment; anything load-bearing from that run is worth re-confirming.
Proxy port rotates per session. 45919 → 39185 is ephemeral binding, not a config change. Read $https_proxy at runtime; never hard-code it.
Clock is a per-session draw. 2.10 → 2.80 GHz is fleet heterogeneity, not a spec change — and 2.80 GHz happens to match the chat sandbox, which mildly strengthens the shared-substrate reading.
Unchanged: init_on_free still not set, Docker daemon still off, kernel still 6.18.5, base image still serial 20260410. The substrate is stable; only the product layer moved.
Every source here is a self-probe. The shared failure mode is over-reading strings output — mistaking a build-toolchain artifact embedded in a binary for the binary's own implementation.
| Claim | Status | Basis |
|---|---|---|
| rclone-filestore is Rust | wrong | Strings show crypto/internal/fips140, go.shape.*, zeebo/xxh3 — it is Go, as rclone has always been. |
| chat has a Rust nightly toolchain | over-read | No installed rustc was ever found; that was a version string inside a shipped binary. |
| sudo absent in chat | untested | Never probed. Not observed-absent. |
| chat egress does not terminate TLS | untested | 403s observed; MITM never checked for. |
| process_api is Rust | holds | Cargo registry paths, hyper, jsonwebtoken. |
| Claim | Status | Basis |
|---|---|---|
| "ip is absent from $PATH" | contradicted | The same transcript shows which ip resolving to /usr/sbin/ip, and ip a returning full interface output. |
| 378 GB disk | artifact | Repeated identically across four mounts; a gVisor reporting quirk. |
| Service account "likely scoped tightly" | partially tested | Two APIs denied; the account's full IAM binding set was never enumerated. |
| Two findings rated "high" | recalibrated | See §4. Neither survives the evidence in the same probe. |
| Claim | Confidence |
|---|---|
| Bright Data proxy — vendor-specific response fields, five distinct exit IPs, residential ASNs | high — near-conclusive |
| Chrome launch flags, process table, s6 stack, boot cmdline | high — directly observable |
| FUSE portal backend protocol | low — explicitly speculative |
| Cross-session persistence | low — backend not observable |
| Absent tooling (strace, lsof) | low — self-reported untested |
Anthropic's public containment write-up describes claude.ai code execution as gVisor; direct probing finds Firecracker. AI Studio now gives us a control case for what gVisor leaves behind — and those fingerprints are absent from the chat sandbox. Both statements may still be true of different code paths. Flagged, not resolved.
Separately: Cowork's claude binary is Bun-compiled, and Bun v2.1.181+ ships the Zig→Rust port of Bun itself, so 2.1.218 embeds a Rust-generation runtime. The discriminating probe — Rust vs Zig markers in the embedded runtime — still has not been run. This is a rewrite of Bun, not of Claude Code, and is unrelated to process_api's Rust.
| Isolation | Egress intent | Agent surface | Built to | |
|---|---|---|---|---|
| chat | microVM + init_on_free | restrict | 4 tools | run untrusted code safely |
| cowork | microVM | restrict, elaborately | full dev agent | run untrusted code safely, at toolchain scale |
| kimi | shared kernel, mitigations off | extend | full desktop | operate a browser like a person |
| ai studio | gVisor syscall interception | none | none — it hosts, not executes | serve your app to the right viewer |
Containment and capability trade against each other, and the first three sit at deliberate points on that curve. The fourth is on a different curve altogether — which is the most useful thing this comparison shows, and the thing a straight vulnerability count would have hidden.