Two things broke in the same week. A Firecracker VM escape (CVE-2026-99999, 6 Nov 2026, front page of Hacker News) showed the isolation layer itself can fail. And the WebMCP Attack Lab (dev.to, 5 Nov 2026) showed a tool description injecting an instruction that bypassed a spending limit - the agent obeyed text that came from a tool, not from its operator. The lesson is the same in both cases: a prompt is not a control, and a report is not evidence. I built cellrun for the gap between those two failures: one task, one fresh cell, and a scan of the tool output before it enters agent context.

What it does

cellrun runs one agent task in a disposable directory with a scrubbed environment and the network off by default, then destroys the cell. Separately, sanitize scans tool / MCP / web output for instruction injection before you trust it. One local, zero-dependency CLI:

cellrun run -- node agent-task.js # fresh cell, network off, destroyed on exit cellrun run --sanitize report.json -- node agent-task.js # refuse to run on HIGH findings cellrun sanitize report.json # exit 1 on HIGH findings cellrun run --copy ./project -- node agent-task.js cellrun run --backend docker -- node agent-task.js cellrun cells # what ran, and whether the network was enforced cellrun audit 

The cell is a fresh workdir with the environment scrubbed to an allowlist (81 host variables dropped in the test run, secrets never leak into the cell), HOME and TMPDIR remapped inside the cell, a 300s default timeout (exit 124), and the task's exit code propagated. Every run writes an audit record (~/.cellrun/audit.jsonl): cell id, command, backend, network on/off plus networkEnforced, exit code, files created, sanitize findings.

The demo below runs the real CLI - a task in a fresh cell, the environment scrub, a sanitize scan finding injected instructions, and the audit trail:

cellrun demo

Honest about what "network off" means

This is the part most tools would fudge, so here it is plainly: network-off is only enforced when the machine has user namespaces (Linux) or when you use --backend docker (--network none). Without either, cellrun degrades honestly - it warns on stderr, records networkEnforced: false in the audit log, and never claims enforcement it does not have. --strict refuses to run degraded at all. The CI run on GitHub's runners proves the degrade path: no namespaces there, so the tests assert networkEnforced: false and pass. On a machine with namespaces, the same tests assert enforcement and a curl inside the cell is blocked.

Two more honest limits in the same spirit. --memory is opt-in because ulimit -v counts virtual memory and Node needs about 2 GB of address space just to start - a value below 2048 breaks Node tasks outright (the process dies at startup, exit 2). And sanitize is a pattern list, not a judge: a novel phrasing can slip past it, MEDIUM findings can false-positive, and a clean result means "no known pattern found", not "safe". The cell is also not a filesystem jail - no mount namespace yet (roadmap).

Where rivals beat us

I compared against the closest tools before building, and cellrun loses on their home turf:

  • devvm - one real VM per project folder, project folder read-write, --clone mode, network tiers. Real VM isolation beats a namespace every time. If you want a VM boundary, use devvm.
  • agent-vm - disposable VM per project, Lima built in, Debian 13 template, MIT. Same trade: a real VM is stronger isolation than a cell. Its boundary is per project; cellrun's is per task, lighter, with no hypervisor or image download.
  • Rivet / Nomos / Gauge - orchestration and governance layers that sit above individual runs. They govern fleets and policies; they are not a local tool you run before a single task.

The wedge: cellrun trades the VM boundary for zero setup (no hypervisor, no image download) and for the two halves the VM tools do not ship - sanitize (scan tool output for injected instructions before it enters agent context) and audit (a record of what ran, whether the network was actually enforced, and what the sanitize scan found). A VM proves the task ran isolated; cellrun also proves what the task was allowed to see and say.

Use it as a gate, not a habit

A cell you remember to use is a habit; a cell your CI enforces is a control. The repo ships a ready-made example (examples/ci-gate/): run agent tasks through cellrun run with --sanitize on their inputs, and a HIGH finding or a degraded network refuses the run. Exit codes are 0 (task exit code propagated on success), 1 (sanitize HIGH / task failed), 2 (usage error, Docker missing, --strict refusal).

Install

Install from source for now - the npm package is not published yet:

git clone https://github.com/techdevfun/cellrun.git cd cellrun npm install npm run build npm link # puts `cellrun` on your PATH 

Node 20 or later. Zero runtime dependencies. TypeScript, strict mode. The test suite is 34 tests (27 unit, 7 end-to-end) plus 2 live tests against the real registries, and CI runs it on Node 20 and 22 - including a real Docker run in CI (a container printing "hello from docker", network enforced, 6.1s).

Sources

PwnEscape Firecracker escape (CVE-2026-99999, 6 Nov 2026, HN front page; the demo config had the jailer not enabled). WebMCP Attack Lab (dev.to, 5 Nov 2026, 75 reactions, 49 comments): tool-description injection bypassing a spending limit. devvm (devvm.dev/docs): one VM per project folder, --clone, network tiers. agent-vm (agent-vm.org): disposable VM per project, Lima built in, MIT.

The code is MIT licensed at github.com/techdevfun/cellrun. If your agent runs tasks with your environment, your network, and your tools, give each task its own cell - and read what the tools told it before it acts on it.