Environment probe · comparative analysis · rev 5

chat / Cowork / Kimi / Grok / AI Studio

Five agent environments, each probed from the inside. Four are built to run untrusted code; the fifth only looks like it is. A sixth submission arrived in the same format and is excluded — §10 explains why, and what standard the others had to meet.

compiled 2026-07-24 chat 06-10 cowork 07-24 kimi 07-23 grok 07-24 · execution proven ai studio 07-24 sixth excluded
containment agent capability chat microVM · 4 tools cowork microVM · dev agent grok microVM · full root + nested virt kimi container · full desktop off axis ai studio gVisor · app preview host not plotted sixth submission — no verified position
Cowork and Grok both occupy the expensive high-containment / high-capability corner, by different routes: Cowork restricts the interior and gates a full dev toolchain through one policy layer; Grok leaves the interior wide open and puts everything on the microVM boundary. AI Studio is drawn off-axis deliberately — it was never built to run untrusted code. The sixth submission has no position because it has no verified measurement to place.
claude.ai chat Claude Cowork Kimi Grok · Hades AI Studio · different threat model sixth · excluded

§1 Substrate & isolation

Where the boundary sits, and how much sits above it.

Platform
Dimensionchatcoworkkimigrokai studio
Isolation modelFirecracker microVMFirecracker microVMcontainerd container (K8s pod)Cloud Hypervisor microVM + containergVisor (runsc) on Cloud Run
Kernelown guest, 6.18.5own guest, 6.18.5shared host, 5.10.134own guest, 6.12.8+user-space, 4.19.0-gvisor
PID 1process_api (Rust)process_api (Rust, vsock)s6-svscancatatonit/bin/bash ./start.sh
Root filesystemext4ext4 + 2× ro squashfsoverlayfs, 114+ layersoverlay: vda 2 G ro + vdb 20 Goverlay (378 GB — gVisor artifact)
Base OSUbuntu 24.04.4 · 20260410Ubuntu 24.04.4 · same serialDebian 12 on LifseaOSUbuntu 24.04.4Debian 12
Instance marker--wiggle----remote_cowork--numeric instance IDhds- hostname prefixCloud Run K_SERVICE
Agent uidrootrootrootroot, all 41 capabilitiesroot

Grok resolves as nested, not either/or

DMI reports cloud-hypervisor while systemd-detect-virt reports docker. Those aren't contradictory: systemd-detect-virt reports container-level virtualisation when it finds any, so it names the inner layer while DMI names the outer one. With /dev/vsock, virtio vda…vdd, a cgroup v2 namespaced root and *.svc.cluster.local resolution, the stack is Kubernetes → Cloud Hypervisor microVM → container → agent.

That puts xAI structurally closest to Anthropic — a hardware-virtualised guest as the real boundary — with a different hypervisor and an extra container layer inside.

Hardening

Settingchatcoworkkimigrokai studio
init_on_free=1setnot setnot setnot in cmdlinen/a
nomodulesetsetnot setnot in cmdlinen/a
Capabilitiesnot probednot probednot probed41/41 incl. ambient
Docker default: 14
not probed
Seccompnot probednot probednot probedfilter active (1), NoNewPrivs=1n/a
MAC (AppArmor/SELinux)n/a (VM)n/a (VM)selinux=0none — earlier claim withdrawnn/a
Spectre mitigationsdefaultdefaultnoibrsibrs_enhanced, stibp, ssbdhost-managed
Nested virtualisationnot probednot probednot probedexposed/dev/kvm presentn/a
Loopback bypassblockedblockedsshd on 0.0.0.0:22not probedn/a

Grok is the only environment where capabilities and seccomp were actually measured, so the not probed cells are a gap in the survey rather than a property of those environments. That asymmetry is worth stating plainly: Grok looks the most permissive in part because it is the only one that has been asked.

§2 Compute & storage

Dimensionchatcoworkkimigrokai studio
CPUXeon @ 2.80 GHzXeon @ 2.80 GHzXeon Platinum @ 2.50 GHzXeon Platinum 8481C @ 2.70 GHz (Sapphire Rapids)masked (unknown)
Cores1 vCPU2 vCPU2 vCPU2 vCPU, no SMT2 vCPU
RAM3.9 GB7.8 GB4.0 GB1.94 GiB — smallest surveyed4.0 GB
Swap / GPUnone / nonenone / nonenone / nonenone / nonenone / none
Disk252 GB252 GB, 30 GB avail40 GB20 GB overlay + FUSE workspace378 GB reported — artifact
Python / Node3.12.3 / 22.22.23.11.15 / 22.22.23.12.12 / —3.12.3 / 24.153.10.12 / 22.23.1
User-data transport4× rclone FUSElocal ext4FUSE portalFUSE grok-filesnone — overlay only
Persistencerclone cache non-determinismephemeral; durability via gitbackend unobservableuntested — see §9fully ephemeral

Where "32Z" comes from

stat -f /home/workdir/artifacts
  Blocks: Total: 9223372036854775807   Block size: 4096

9223372036854775807 = 2⁶³ − 1 = INT64_MAX
INT64_MAX × 4096 = 32.0000 ZiB exactly

The FUSE daemon returns INT64_MAX blocks — the conventional sentinel for unbounded — and df renders it as 32Z. Like AI Studio's 378 GB, it is a reporting artifact, not a provisioned allowance. Two of five environments now report a headline disk figure that means nothing.

§3 Egress — four postures, no two alike

The most informative axis in the survey, and now the one with the widest spread.

Dimensionchatcoworkkimigrokai studio
Mechanism403 intercept, x-deny-reasonTLS-terminating MITM + own CABright Data residential proxyconnection never completesnone
Intentrestrict reachrestrict reach, across toolchainsextend reach past anti-bot defencesrestrict absolutely; grant per serviceno policy
Does anything answer?yes — 403yes — proxiedyes — via proxyno — transport failureyes — direct
Metadata endpointnot testedhard-blockednot reportedunreachable (transport)reachable — token extractable
How packages arriveallowlisted domainsallowlisted via proxyregistries openper-service brokers on the internal networkdirect
Anti-detectionnonenoneautomation flags stripped, UA spoofednonenone
Ingress controln/an/asshd, key-onlyn/anginx + Lua token bridge
grok, direct targets:
  https://pypi.org        -> CURL_FAIL
  https://github.com      -> CURL_FAIL
  https://www.google.com  -> CURL_FAIL
  http://169.254.169.254  -> CURL_FAIL   plain HTTP, link-local — no DNS, no TLS

grok, broker:
  http://35.245.43.102/pypi/simple/  -> 200  remote_ip 35.245.43.102

Cage, disguise, wall, absence

Anthropic's proxies are a cage — something answers, with a reason. Kimi's is a disguise, extending reach past defences that would otherwise block it, via residential exit IPs. AI Studio has no policy at all.

Grok's is a wall. Nothing answers on any direct target — including the metadata address, which needs neither name resolution nor a TLS handshake, ruling out DNS filtering and certificate problems as explanations. Reachability is granted by internal brokers, one per upstream, resolving as Kubernetes services in a hades-openbar namespace. You reach PyPI because a PyPI broker exists, not because PyPI is permitted.

§4 Interior posture — the Grok inversion

Strictest outward, most permissive inward. Both by design.

CapInh/Prm/Eff/Bnd/Amb : 000001ffffffffff   = 41 of 41 capabilities
Docker default CapEff    : 00000000a80425fb   = 14
NoNewPrivs: 1   Seccomp: 2 (1 filter)   AppArmor: absent
/dev/kvm: present        vmx in cpuinfo: 4 lines (2 procs × flags + vmx flags)

All five capability sets full, including ambient — meaning privilege survives execve into ordinary unprivileged binaries, so it does not drop when the agent shells out. Very little sets that deliberately. Containment inside the guest therefore rests on one seccomp filter and, decisively, on the microVM underneath.

That is coherent rather than careless. If the hardware boundary is what you trust, in-guest capability restriction buys comparatively little and costs real tooling friction. It is the opposite bet from Cowork, which restricts the interior heavily — Docker daemon off, commit signing enforced, egress terminated and inspected — while running on a comparable microVM. Same class of boundary, opposite philosophy about what happens above it.

Grok's first report was wrong about this

The initial write-up listed "AppArmor profiles present" among its security layers. Raw output shows no AppArmor and no /proc/self/attr/current. The claim was withdrawn as soon as output was required instead of summary — the clearest argument in this whole survey for demanding transcripts over prose, including from oneself.

§5 AI Studio is not a peer — scoring it as one is a category error

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, 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.

FindingAs filedCalibratedWhy
Metadata server reachable; OAuth token extractablehighdefault · mitigatedEvery Cloud Run container reaches 169.254.169.254; platform default. IAM scoping is the control, and it held — two API calls returned 403, Cloud Resource Manager SERVICE_DISABLED.
Model API key in plaintext environmenthighreal, severity undeterminedMechanism genuine — any transitive npm dependency reads process.env, egress open. Severity depends on whether the key is per-applet or shared platform; never established.
DISABLE_AUTH_BRIDGE disables ingress authnot filedhighest-consequence controlDocumented and warned in-file. Still the one variable whose misapplication turns an authenticated preview into an open one. Unmentioned in the source audit.
Unrestricted egresshighaccurate, mis-framedA preview host that cannot reach the internet cannot serve most applications. Belongs in the threat model, not the vulnerability list.

None of which makes it safe for untrusted code — root execution, open egress and secrets in the process environment compose badly. The correction is to the framing, not the facts.

§6 Product posture

Five product classes, not five sizes of one thing.

Dimensionchatcoworkkimigrokai studio
Runtime on top4-tool interfaceClaude Code CLI 2.1.218s6 stack + Jupyter kernelgrok-computer-server.mjs + 16 skillsnginx + Go control plane + Vite
Interaction modelone-shot tool executionagent: MCP, hooks, sub-agents, scheduled tasksremote desktop: Xvnc + Chromium + pyautoguiskill-augmented tool useapp preview behind an auth bridge
Skills abstraction8 public skillsinherits chat'sFUSE-mounted skills16 modules in /root/.grok/skills/none
DatabasesnoneRedis + Postgres 16.13, in-boxnot reportednot probednone
Containers / VMsabsentDocker present, daemon offnot reportedno Docker — but /dev/kvm presentabsent
Systems toolchaingcc, JavaRust, Go, strace, lsofminimal imagegcc 13.3.0, magika, bfsJS/TS + Python only
Reach to user's machinenoneremote-devices bridgeSSH in, key-onlynonenone
Git posturea capabilitycentral — commit signing, stop hooksnot reporteda capabilitynot a product concern

Reading the five

chat — hardened ephemeral scratchpad. Reason, generate documents, run short code.

cowork — git-native software-engineering agent. Docker tooling, proxy trust bundle and signing hooks 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.

grok — document and media production environment with a permissive interior, sealed outward. Skills are the organising abstraction and the smallest RAM allocation of the five.

ai studio — application preview host. It gives the model a web server and the user an authenticated URL.

Three of the five now use a bundled-skill directory with Markdown guides and helper scripts. That convergence is the clearest sign of a settling pattern in how these environments extend a model's reach.

§7 Cowork drift — week over week

2026-07-15 → 2026-07-24. Only fields that moved.

Field07-1507-24
claude_cli2.1.2102.1.218
agentclaude-code_2-1-210_agentclaude-code_2-1-218_agent
runnerstaging-a54e7c22brelease-1186d93b9-ext
cpuXeon @ 2.10 GHzXeon @ 2.80 GHz
https_proxy127.0.0.1:45919127.0.0.1:39185

What the drift says

staging → release. The 07-15 findings were taken against a pre-release runner and should not be assumed to describe the shipping environment.

Proxy port rotates per session — ephemeral binding, not a config change. Read $https_proxy at runtime.

Clock is a per-session draw. 2.10 → 2.80 GHz is fleet heterogeneity, and 2.80 GHz matches the chat sandbox, mildly strengthening the shared-substrate reading.

Unchanged: kernel 6.18.5, base image serial 20260410, Docker daemon off. The substrate is stable; only the product layer moved.

§8 Verification — the nonce, and why it changes the series

Grok is the first environment here whose execution was proven rather than assumed.

issued : printf '%s' '<nonce invented in the requesting conversation>' | sha256sum
returned: c3b6cb302ffb9d27f91bdc016c80a141b838884e84a49810b2452e9ecda78d37
recomputed independently:
          c3b6cb302ffb9d27f91bdc016c80a141b838884e84a49810b2452e9ecda78d37   

A digest of a string with no prior existence cannot be recalled and cannot be derived. Producing it requires running code. Every other environment in this survey is trusted to have executed its probe; only this one has demonstrated it.

Three further Grok claims were verified by arithmetic rather than assertion: the INT64_MAX × 4096 workspace figure, the capability mask against a full set, and the benchmark against theoretical peak (76.1% — where real BLAS lives, and safely under the ceiling that a fabricated submission exceeded).

The standard, restated

Ask for values that are cheap to read and expensive to guess: a nonce digest first, then raw /proc/self/cgroup with byte count, sched_getaffinity, unrounded /proc/meminfo, time_ns() bracketing, a benchmark run five times with an implied-FLOPS sanity division, and DMI for the virtualisation class. Then two procedural rules: do not supply prior reports as context, and require the transcript, not the write-up.

§9 Evidence quality & corrections

Every source here is a self-probe. The shared failure mode is over-reading output and summarising instead of transcribing.

ClaimSourceStatusBasis
rclone-filestore is RustchatwrongStrings show crypto/internal/fips140, go.shape.* — it is Go.
chat has a Rust nightly toolchainchatover-readA version string inside a shipped binary, not an installed compiler.
chat outputs persist across sessionschatwrongThe rclone cache made it look durable within a session. It was not.
process_api is RustchatholdsCargo registry paths, hyper, jsonwebtoken.
"ip is absent from $PATH"ai studiocontradictedSame transcript shows which ip resolving and ip a returning output.
378 GB diskai studioartifactRepeated identically across four mounts — a gVisor quirk.
"AppArmor profiles present"grokwithdrawnNo AppArmor, no /proc/self/attr/current.
Workspace is 32Zgrokproven — and a sentinelINT64_MAX × 4096 = 32.0000 ZiB. Not a provisioned size.
Workspace persists across sessionsgrokuntestedMarker written and hashed in one session; cross-session read never performed. This is exactly the error chat made.
/proc/cpuinfo hashgroknot recomputableDigest supplied, second processor block elided. Content strongly corroborating on its own.
Bright Data proxy identificationkimihighVendor-specific response fields, five distinct exit IPs, residential ASNs.
FUSE portal backend protocolkimispeculativeSelf-described as such.

Still unresolved

Anthropic's public containment write-up describes claude.ai code execution as gVisor; direct probing finds Firecracker. AI Studio supplies a control case for what gVisor leaves behind — df returning Function not implemented, CPU model unknown — and neither fingerprint appears in the chat sandbox. Both statements may 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 has still not been run. This is a rewrite of Bun, not of Claude Code.

And a survey-wide gap: persistence has never been tested anywhere. Four of five environments claim or imply a durable workspace; none has been read from a second session. The one environment where it was checked — chat — turned out to be wrong.

§10 The sixth submission, and why it has no column

It arrived in this format, with code blocks, raw JSON, benchmarks and its own comparison table. It is not the product of execution.

It was offered as a column and declined — not because its findings were doubtful, but because there is no measurement to place in a cell. Load-bearing items:

How it got convincing

Its comparison table described AI Studio's disk as "378 GB (artifact)". That parenthetical is not a fact — it is an editorial judgement written into this document, and it appears nowhere in the original AI Studio probe. Its presence proves this comparison was in context when the submission was produced, and every other figure in that table matched ours exactly.

The rule that follows: supplying prior reports as context manufactures the appearance of corroboration. Consistency carries no information when the corpus was in context. Only claims that could contradict the supplied material are evidence — which is precisely why Grok's nonce, capability mask and egress failures count, and its vocabulary does not.

Error is not fabrication. §9 publishes this series' own mistakes: calling a Go binary Rust is a misreading of a real artifact, and the finding survives correction. Here there is no underlying observation to correct toward — so no part of it can be salvaged, including the parts that look reasonable. A number that is right by coincidence is indistinguishable from one that is right by observation.

§11 Summary

IsolationInteriorEgressBuilt to
chatmicroVM + init_on_free4 tools, no persistencerestrict — 403 answersrun untrusted code safely
coworkmicroVMrestricted: daemon off, signing enforcedrestrict — MITM answersrun untrusted code at toolchain scale
kimishared kernel, mitigations offfull desktop, rootextend — residential proxyoperate a browser like a person
grokmicroVM + containerfully permissive — 41 caps, KVMwall — nothing answersproduce documents and media inside a trusted boundary
ai studiogVisor syscall interceptionroot, secrets in envnoneserve your app to the right viewer
sixth submissionexcluded — no verified measurement. See §10.

The survey's central finding has held across five environments: containment and capability trade against each other, and every vendor picks a different point — but the interesting variation is not how much containment there is, it is where it is placed. Cowork puts it above the boundary, Grok puts it all at the boundary, Kimi puts it in the browser, AI Studio puts it at the front door. Reading a vulnerability count would have hidden every one of those choices.