How to Lock Down AI Agent Code: subprocess, Docker and microVM — Three Levels of Protection
If an AI agent writes and executes code on its own, all of your security comes down to where that code runs. A write-up on Machine Learning Mastery compares three boundaries: a restricted subprocess, a Docker container, and a Firecracker microVM via E2B. All three are run against the same "malicious" programs: eat CPU and memory, spawn processes, read secrets, reach the network. Meanwhile, the agent sees a single run_python tool and has no idea what sits behind it.
AI-processed from Machine Learning Mastery; edited by Hamidun News
You gave your agent a "run Python code" tool — and at that moment you got not just an assistant, but remote code execution, even if it happens at the model's request. The model can make a mistake, or it can receive a malicious instruction from a planted page or file. So the question is not "is the agent smart," but "what can a bad program reach once it starts running." The authors of the Machine Learning Mastery write-up answer it in practical terms: they build three sandboxes and run the same attacks against each one.
One tool, swappable backends
The architecture is simple. The agent knows a single tool, run_python: it accepts a string of code and returns stdout, stderr and an exit code. The model's code is never executed inside the agent's own process. It goes to a sandbox object with a run(code) method, and any class with that method will do. So changing the isolation level does not require touching the agent's logic: you swap the backend and that's it. A non-zero exit code is flagged as an error, and the model sees this and can correct itself.
An important principle from the Docker blog, which the authors apply to all levels: file access, network policy and secrets are set by the infrastructure before the agent starts, not by the agent itself.
Three boundaries
Subprocess is the lightest option. It is a child process with limits on CPU time, memory (address space) and the size of files it can write. Around it:
- launch in isolated mode
python -Iin a temporary folder; - a clean environment with no API keys and no home directory;
unshare --net, that is, a private empty network;- output redirected to files, so the file-size limit also protects against a flood of
print; - on timeout the entire process group is killed.
If the constructor cannot enable network isolation, it fails with an error rather than silently leaving the network open. When running as root, the code is first downgraded to the nobody user.
But this level comes with an honest caveat: the kernel and file system remain the host's. The code runs as you, on your file system, and does not hide your files. The process-count limit counts all of the user's processes, so it only makes sense for a dedicated user; on an ordinary laptop it is skipped.
A Docker container adds namespaces and cgroups, but these are still the same processes on the host kernel. The Docker documentation states plainly that without explicit settings a container has no resource limits, so the sandbox sets memory, CPU count and process count (in the example, 256 MB, one CPU, 64 pids). And escapes do happen: in November 2025, three vulnerabilities in runc allowed breaking out of a container.
A Firecracker microVM (in the example, via E2B) gives each sandbox its own kernel behind a hypervisor. Docker calls this a hardware boundary, and AWS states that in Lambda on Firecracker the kernel is not shared between sessions. It is the most expensive option in terms of latency, and it requires an E2B account with a key.
What to do about it
The authors test each level against identical hostile programs: exhaustion of CPU, memory, processes and disk, plus attempts to read files and reach the network. Then, in bench.py, they measure the latency cost of stronger isolation. The available part of the material contains no measurement figures, so run the benchmark on your own hardware: latency depends heavily on the environment.
The practical logic of choosing is as follows:
- Subprocess is suitable for local experiments and code you almost trust. It requires Linux or WSL.
- Docker with strict flags suits internal tools where you are ready to accept the risk of an escape.
- MicroVM is the choice for third-party and untrusted input and for multi-tenant products where an escape means an incident.
And most importantly: do not leave the decision about its own sandbox to the agent. Secrets, network and files are determined by whoever deploys the infrastructure. If you want a ready-made solution rather than a self-built one, the authors have a separate article on five hosted sandboxes; here everything is assembled by hand so you can see exactly what those platforms do under the hood.
- Nov 12, 2026Spring AI and Bedrock AgentCore: A Java Agent in Production with One Annotation and Two Endpoints
- Nov 12, 2026Semantic diff for LLM-generated policies: 18 “changed” lines reveal 2 bugs
- Nov 12, 2026Bedrock Knowledge Base Learns to Choose Search Depth: From 0 LLM Calls to Agentic RAG
- Nov 12, 2026Anthropic Buys $3.4 Billion in Gas Turbines: 1.7 GW to Power AI
Key Questions Answered
What are the key details on One tool, swappable backends?
The architecture is simple. The agent knows a single tool, run_python: it accepts a string of code and returns stdout, stderr and an exit code. The model's code is never executed inside the agent's own process. It goes to a sandbox object with a run(code) method, and any class with that method will do. So changing the isolation level does not require touching the agent's logic: you swap the backend and that's it. A non-zero exit code is flagged as an error, and the model sees this and can correct itself.
What are the key details on Three boundaries?
Subprocess is the lightest option. It is a child process with limits on CPU time, memory (address space) and the size of files it can write. Around it: launch in isolated mode python -I in a temporary folder; a clean environment with no API keys and no home directory; unshare --net, that is, a private empty network; output redirected to files, so the file-size limit also protects against a flood of print; on timeout the entire process group is killed.
What to do about it?
The authors test each level against identical hostile programs: exhaustion of CPU, memory, processes and disk, plus attempts to read files and reach the network. Then, in bench.py, they measure the latency cost of stronger isolation. The available part of the material contains no measurement figures, so run the benchmark on your own hardware: latency depends heavily on the environment. The practical logic of choosing is as follows: Subprocess is suitable for local experiments and code you almost trust.
Test Frontier LLMs & Autonomous Agents in One Workspace
Run Claude Opus 5.5, GPT-6, Gemini 3.1, and DeepSeek side-by-side in Nomad AI (nomadnet.ai) — unified model routing, deep research, and multimodal workflows under one subscription.
The AI world, distilled — once a week
Seven stories that actually mattered, hand-picked. No noise, no reposts, no press releases.
Done! Check your inbox for a confirmation.