How do you safely sandbox an AI agent that runs code?
Run the agent's code in an isolated sandbox with no network beyond the hosts you allow, only the credentials the current task needs, and hard limits on time and money. On Nodus that is one Sandbox spec: network access is
Run the agent's code in an isolated sandbox with no network beyond the hosts you allow, only the credentials the current task needs, and hard limits on time and money. On Nodus that is one Sandbox spec: network access is off by default, Secrets are mounted by name, and maxLifetime, maxCostUSD and a project Budget end anything that runs away. Then assume the boundary can fail anyway, and keep nothing inside it you could not afford to lose.
We build Nodus, so the Nodus parts below are copied from our docs as of November 1, 2026. The threat model and the list of controls come from public guidance by the NVIDIA AI Red Team and Anthropic, linked where they are used.
What actually goes wrong when an agent runs code?
The main risk is not a model that turns evil. It is a model that reads hostile text and follows it. The NVIDIA AI Red Team names indirect prompt injection as the primary threat to coding agents, arriving through malicious repositories, pull requests, git history, AGENT.md files and MCP server responses.
Once the agent is steered, it can do three kinds of damage with ordinary commands:
- Send data out: your source code, an
.envfile, a cloud key from your home directory. - Stay behind: a git hook, a shell profile edit or an MCP config change that runs again later, outside any sandbox.
- Burn resources: a loop, a fork bomb or a forgotten process that keeps a machine busy for days.
Approval prompts help less than they seem. The same NVIDIA post points out that people who approve every action soon approve without reading. And it notes that filters on tool calls miss what happens inside a subprocess, because a blocked tool can be reached through an allowed one. That is why the controls below are enforced by the operating system or the platform, not by the agent's own prompt.
Where should the agent's code run?
Pick the boundary by what the agent touches. If it works on a repository on your laptop while you watch, an OS-level sandbox on that laptop is enough. If it runs unattended, runs code from strangers, or runs many copies at once, move it to a remote sandbox that never had your files or credentials in the first place.
Claude Code's Bash sandbox is a good example of the local kind. The operating system limits writes to the working directory and a temp directory, and network traffic goes through a proxy whose allowed domains start empty. It uses Seatbelt on macOS and bubblewrap on Linux. Its docs are also clear about the gap: the sandbox covers shell commands only, while Claude's file tools, MCP servers and hooks run outside it.
A remote sandbox closes that gap by moving everything the agent executes onto another machine. NVIDIA lists virtualization that separates the sandbox kernel from the host kernel as a recommended control. On Nodus, production CPU Sandboxes run behind a user-space kernel that passes only a filtered set of system calls to the host.
Each Sandbox runs as a non-root user with no Linux capabilities, in its own cgroup limited to the CPU and memory you asked for and 256 processes. Machines serve one organization at a time, as the Sandbox isolation page describes.
How do you lock down the network without breaking the agent?
Start with no network and add named hosts as the task needs them. NVIDIA calls egress control to known-good locations mandatory, because a closed network is what stops a prompt-injected agent from sending your key somewhere.
A Nodus Sandbox has three egress policies, set in spec.network.egress.policy:
-
Deny, the default, gives the Sandbox no route out at all. -
AllowListlets HTTP and HTTPS traffic reach the DNS names you list, such asgithub.com, or*.domainpatterns, through an injected proxy. -
Openreaches the public internet, but never other Sandboxes, the machine it runs on or Nodus services.
Private address ranges and cloud metadata addresses stay blocked under every policy. A blocked connection raises an EgressDenied event on the Sandbox, which is a useful signal: an agent that suddenly tries to reach a host it never needed is worth a look.
The rule we use is to keep Deny for code execution, use AllowList for package installs and git, and treat Open as an exception with a reason written next to it. The Sandboxes guide has the full field reference. The Python SDK does not accept an allow-list yet, so set AllowList in a manifest.
How do you give an agent credentials without handing them over?
Assume the agent can read every credential you give it. Our own isolation docs say it plainly: anything in a Sandbox's environment or files is readable by the code running there, and with Open egress that code can send it anywhere. So the work is in choosing what goes in.
Three habits do most of the work:
- Give each task its own narrow key. A Nodus API key can be limited by scope, project and expiry, for example
nodus create apikey ci --scopes jobs:write,volumes:read --projects research --expires 720h, and a deleted key stops working within 30 seconds everywhere (API keys and scopes). - Pass secrets by reference, never by pasting. A Nodus Secret is mounted as env vars and as read-only files under
/run/secrets/<secret>/<key>. A command whose literalenvvalue equals a stored Secret value is refused withSecretValueInEnv, and secret values are redacted from logs. - Never pair a powerful secret with an open network. If a task needs both, split it into two Sandboxes: one with the key and
Deny, one with the network and no key.
NVIDIA goes further and recommends secret injection that keeps values away from the agent entirely. Claude Code's sandbox can mask environment variables and credential files for local work. For a remote sandbox, the closest equivalent is a key that can do very little and expires soon.
How do you stop a runaway agent from running up a bill?
Put a hard limit on time and on money, because idle detection does not catch a busy loop. The Nodus docs count a running process as activity, "including one that prints nothing for hours", so a stuck process keeps its Sandbox running until something else stops it.
Here is the worst case we plan for, priced from the Nodus pricing page, where a 4 vCPU, 16 GiB CPU Sandbox is listed at $0.1054/hr. A bad prompt or a bug leaves 50 parallel agents each stuck in a loop:
| What stops the 50 stuck Sandboxes | Each runs for | Worst-case total |
|---|---|---|
Nothing but maxLifetime: 720h, the maximum |
720 hours | $3,794.40 |
The default maxLifetime of 24 hours |
24 hours | $126.48 |
maxCostUSD: "1.00" on each Sandbox |
about 9.5 hours | $50.00 |
A $20 project Budget with action: Block
|
until the project has spent $20 | $20.00 |
The math: $0.1054 x 720 hours x 50 is $3,794.40, and $0.1054 x 24 x 50 is $126.48. A $1 cap ends each Sandbox after $1 / $0.1054, about 9.5 hours, so 50 of them cost at most $50.00. The Budget caps the whole project at $20 no matter how many agents run.
A per-Sandbox cap plus a project Budget turns an open-ended bill into a number you chose in advance.
The dollar cap stops a stuck Sandbox sooner than either lifetime limit.
Both limits are enforced by the platform. The Budgets guide says limits are checked before paid work starts and again every few minutes while it runs. A Sandbox that hits its cap stops with MaxCostReached and answers 402 until you raise it. For the same idea applied to GPU jobs that coding agents launch, see how to cap the GPU spending of an AI coding agent.
What does a complete agent sandbox spec look like?
This manifest puts every control above into one file. It extends the quick start in the Nodus Sandboxes guide with an allow-list, a Secret and a longer lifetime:
apiVersion: nodus.dev/v1
kind: Sandbox
metadata:
name: agent-task-42
spec:
image: nodus/agent-tools # Python 3.12, Node 22 and git
resources:
cpu: "4"
memory: 16Gi
network:
egress:
policy: AllowList
allow: ["github.com", "pypi.org", "files.pythonhosted.org"]
secrets: [repo-read-token] # mounted as env vars and /run/secrets/repo-read-token/
lifecycle:
idleTimeout: 5m
onIdle: Stop # keep /workspace, stop paying for compute
maxLifetime: 24h # deleted after 24 hours whatever it is doing
maxCostUSD: "1.00"
Create it with nodus apply -f sandbox.yaml, then let the agent drive it with nodus exec sb/agent-task-42 -- <command>. Commands run in /workspace as a non-root user, and nodus get sb/agent-task-42 shows the cost so far.
Creating the same name and spec again reconnects to the existing Sandbox, so an agent can run the same create step every time it restarts. Put the project's Budget in place once, and every agent Sandbox in that project counts against it.
Here is the full checklist, with the source of each control:
| Control | Recommended by | Nodus setting |
|---|---|---|
| Block egress except known hosts | NVIDIA (mandatory) |
egress.policy: Deny or AllowList
|
| Keep writes inside the workspace | NVIDIA (mandatory) | Separate machine; work in /workspace
|
| Separate the kernel from the host | NVIDIA (recommended) | User-space kernel on production CPU Sandboxes |
| Keep secrets away from the agent | NVIDIA (recommended) | Scoped, expiring keys; Secrets by reference |
| Clean up old sandboxes | NVIDIA (recommended) |
maxLifetime, onIdle: Delete for one-off tasks |
| Cap spend per run and per project | Nodus docs |
maxCostUSD and a Block Budget |
When is a local sandbox the better choice?
A local OS-level sandbox wins when the agent works on your own repository, in front of you, in short sessions. Claude Code's Bash sandbox costs nothing extra, needs no upload, and lets the agent see the exact files you see. The extra round trip to a remote sandbox buys you little there.
A remote sandbox is the better choice when the agent runs without you, runs code from people you do not know, or runs as many parallel copies. Local sandboxes also leave some pieces outside the boundary by design, such as MCP servers and hooks in Claude Code. For a side-by-side of hosted options, including E2B's pause with memory intact, see which sandbox is best for running AI agent code and Nodus vs E2B.
FAQ
Is a Docker container enough to sandbox an AI agent?
A plain container shares the host's Linux kernel, so a kernel bug reachable from inside is reachable from the agent. NVIDIA recommends a microVM, Kata container or full VM for that reason. Nodus development nodes use a standard container runtime, and the docs say to run untrusted code only on production nodes with the full boundary.
Should an agent sandbox ever have internet access?
Only to the hosts the task needs, and only when the sandbox holds no secret worth stealing. An allow-list of github.com and your package index covers most coding work. Full internet access is the setting most likely to turn a prompt injection into a data leak.
What happens to the agent's work when its sandbox stops?
On Nodus the default continuity mode, Snapshotted, keeps the filesystem changes, with /workspace first among them, and takes a snapshot about every 10 minutes while the Sandbox runs. Running processes never survive a stop, so start servers again from your code. Use Ephemeral when every task should start clean.
Can an agent raise its own spending cap?
Not if its key cannot write to the Sandbox or Budget. Give the agent a key scoped to what the task needs, and keep Budget changes with a person. On Nodus a maxCostUSD can be raised but never lowered, so set it low at the start.
Does sandboxing make prompt injection impossible?
No. It limits what an injected instruction can reach: the files in the sandbox, the hosts on the allow-list, the credentials you mounted and the money under the cap. That is why the last rule is to keep the blast radius small, not to trust the boundary.
Originally published on the Nodus blog.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.
