An AI coding agent can turn a small request into shell commands, package installs, file writes, and network calls in minutes. That is useful right up to the moment it inherits a home directory, a cloud credential, or a writable production configuration it never needed.
The fix is not another long prompt telling the agent to be careful. Define the execution boundary before the run begins. An AI agent sandbox manifest is a small, reviewable contract that declares what the run may read, write, connect to, use, spend, and leave behind. It makes a risky default explicit—and makes a safe default repeatable.
This guide shows a practical manifest design for coding and automation agents, plus the runtime checks that make the document real.
Why a prompt is not an execution boundary
Instructions are useful for planning. They are a weak control for processes that can execute code. A generated install script can read inherited environment variables. A test can write outside its intended directory. A dependency hook can make an outbound request before the agent has explained why it needs one.
Current sandbox platforms converge on the same basic idea: isolate the filesystem and execution environment, then explicitly expose the ports, mounts, and external systems a task needs. The hard part for a product team is not choosing a container or microVM. It is deciding—and recording—those allowed capabilities for every run.
Without a contract, teams accumulate exceptions:
- “Mount the whole repo so the test passes.”
- “Forward my credentials just for this integration.”
- “Allow the internet; package installation is easier.”
- “Keep the machine around in case we need to inspect it.”
Each exception may be understandable alone. Together, they create an agent runtime that is difficult to review, reproduce, or safely operate for more than one user.
What an AI agent sandbox manifest should declare
A manifest is configuration, not a policy essay. Keep it near the task definition or repository, validate it in CI, and resolve it into runtime settings. Start with six questions.
| Boundary | Declare | Safe default |
|---|---|---|
| Files | Read-only inputs, writable work area, forbidden paths | No host mounts; one writable scratch directory |
| Network | Named destinations and protocols | Deny outbound traffic |
| Identity | Scoped, short-lived capability handles | No inherited environment credentials |
| Execution | Image, user, commands, CPU/memory/time | Non-root; allowlisted entrypoints |
| Data | Retention, artifacts, logs, redaction | Delete workspace after retention window |
| Spend | Time, token, tool-call, and request ceilings | Small task-level budgets |
The key design choice is to describe capabilities rather than implementation. repo_read and artifact_write remain meaningful if you move from a local container to a remote sandbox. Your adapter can turn them into mounts, policies, and firewall rules for the selected runtime.
A minimal manifest, then a safer one
Here is a deliberately compact example for an agent asked to update documentation and run unit tests. YAML is only a convenient syntax; JSON or a typed configuration object works just as well.
version: 1 run: purpose: "Update API documentation and run unit tests" max_duration_seconds: 900 resources: cpu: 2 memory_mb: 4096 filesystem: mounts: - source: repo target: /workspace mode: read_only - source: run-scratch target: /scratch mode: read_write writable_paths: - /scratch forbidden_paths: - /home - /root - /var/run/docker.sock network: default: deny allow: - host: registry.npmjs.org ports: [443] identity: environment: allowlist capabilities: [] cleanup: delete_workspace: true retain_artifacts_hours: 24 This is already better than “run in Docker.” It says the repository is an input, not a writable host directory. It gives generated files a place to go. It rejects inherited credentials and denies the network except for one explicit dependency registry.
For an agent that must open a pull request, add a narrowly scoped capability rather than a generic token:
identity: environment: allowlist capabilities: - type: source_control repository: acme/docs-site actions: [create_branch, push_branch, create_pull_request] expires_after_seconds: 1200 require_approval_for: [push_branch, create_pull_request] artifacts: collect: - /scratch/test-results.xml - /scratch/diff.patch redact: - "(?i)(api[_-]?key|token|password)\\s*[:=]\\s*\\S+" The runner should exchange that declaration for a short-lived credential at execution time. Do not put a secret value in the manifest, and do not copy a developer’s entire environment into the sandbox.
Separate inputs, outputs, and state
Many unsafe setups make one checkout serve three jobs: trusted source input, agent workspace, and durable state. Split them.
- Stage a specific commit as a read-only input.
- Create a fresh writable overlay or worktree for the run.
- Export a patch, build artifact, test report, or pull request as the output.
- Persist only state with an explicit owner and retention rule.
That structure changes recovery. If an agent produces a bad edit, discard the overlay. If a task needs to resume, restore a named snapshot with its manifest and input commit, not an opaque machine whose history is unknown. It also prevents one tenant’s leftovers from becoming another tenant’s context.
Avoid broad host mounts even when their paths look harmless. A workspace can contain symlinks, hard links, credential helper settings, local package caches, or configuration that changes what a command means. Resolve mounts before launch, reject links that escape the staged root, and record the resulting digests in the run receipt.
Egress needs names, not a vague “internet” switch
Network access is often where a good sandbox becomes porous. Start with no outbound access. When a task needs a service, add an allowlist entry that includes the hostname, protocol, port, reason, and, where practical, an expected API path or proxy policy.
network: default: deny allow: - host: api.github.com ports: [443] reason: "Create approved pull request" - host: registry.npmjs.org ports: [443] reason: "Install lockfile-pinned dependencies" block_private_ranges: true proxy_required: true An egress proxy can enforce the list, log attempts, redact sensitive headers, and prevent access to private addresses. Treat DNS as part of the policy; otherwise a hostname allowlist can be bypassed through resolution or redirects. Also distinguish downloading a package from publishing one. They are different capabilities with different risk.
Make cleanup a lifecycle, not a shell command
An agent sandbox that survives past its task is a cost and data-retention decision. The manifest should state how a run ends in every path: success, timeout, cancellation, runner crash, and failed cleanup.
Use a lifecycle like this:
create isolated run → stage verified inputs → issue scoped capability → execute with limits → collect approved artifacts and evidence → revoke capability → destroy workspace → verify destruction The order matters. Revoke access before deleting state. If destruction fails, quarantine the sandbox, deny a new lease, alert the operator, and preserve only the minimum forensic evidence. Never solve a failed cleanup with an unscoped recursive delete on the host.
For longer tasks, set a lease. A worker must renew its lease while it is healthy; otherwise the scheduler cancels it and begins revocation and cleanup. This prevents abandoned jobs from retaining compute or credentials indefinitely.
Enforce the manifest at three points
A manifest is trustworthy only if the system rejects drift. Enforce it before, during, and after execution.
1. Admission checks
Before provisioning, validate schema and policy:
- Require a purpose, owner, expiry, and resource caps.
- Reject writable mounts outside approved workspace roots.
- Reject wildcard network rules for unattended runs.
- Reject root execution and host Docker socket access.
- Require an approval reference for write, publish, or production actions.
2. Runtime checks
At launch, resolve aliases into immutable values: image digest, source commit, mount paths, network rules, and issued capability IDs. Then enforce CPU, memory, disk, process, and wall-clock limits outside the agent process. A model cannot reliably police its own budget after it is stuck in a loop.
Log denied filesystem and network attempts as structured events. A denial is useful feedback: it may reveal an incomplete manifest, a bad assumption, or malicious instructions hidden in a repository.
3. Exit checks
On exit, publish a receipt before destruction. A helpful receipt contains the manifest digest, input commit, image digest, capability grants, executed command hashes, artifact checksums, denied actions, final status, and cleanup result. It records what happened without storing private reasoning or raw secrets.
{ "run_id": "run_8a1", "manifest_sha256": "…", "input_commit": "4c1f…", "network_denials": 2, "artifacts": [{"name": "diff.patch", "sha256": "…"}], "cleanup": {"workspace_destroyed": true, "capabilities_revoked": true} } Start with task classes, not one enormous policy
Most teams need a few reviewable templates, not a unique policy for every prompt. Create task classes such as:
- Read and explain: read-only source, no network, no credentials.
- Test and patch: isolated writable overlay, package registry proxy, no deployment credentials.
- Pull request: patch policy plus a short-lived source-control capability and approval gate.
- Data job: data-specific mount, no source-control access, output bucket with a write-only prefix.
Keep the base class restrictive and make each added capability visible in code review. A task that genuinely needs a browser, a database, and cloud access should explain why each boundary is necessary. That friction is useful architecture feedback.
Common mistakes that make sandboxes less safe
Treating a container as the entire control. A container does not automatically remove inherited environment variables, forwarded SSH agents, privileged sockets, or broad network access.
Giving every task the same image. A test runner, a document agent, and a deployment worker need different tools and identities. Smaller images reduce surprise and speed up review.
Logging everything. Full command output can include customer data and tokens. Log decisions, metadata, hashes, and explicit artifacts; redact before persistence.
Making persistence the default. Preserve state only when resumability is a stated requirement. Otherwise, use an ephemeral workspace and retain the evidence needed to reproduce the result.
Using one “AI token.” Capability-specific, short-lived credentials are easier to revoke, audit, and limit than a single powerful secret.
A practical rollout plan
Do not wait for a perfect microVM platform. Start by inventorying what current agents can access: paths, sockets, environment variables, network destinations, cloud roles, and cleanup behavior. Turn the most common safe task into a manifest template, run it in report-only mode, and compare requested capabilities with actual use.
Then block the high-risk defaults: host home directories, production credentials, unrestricted egress, root execution, and indefinite workspaces. Add approval gates for capabilities that create external side effects. Finally, make the manifest digest and run receipt required evidence for pull requests and production operations.
The payoff is not only security. A sandbox manifest makes agent runs easier to debug, reproduce, meter, and hand off. When a run fails, you can answer concrete questions: which input was used, what it was allowed to touch, what it actually tried to do, and whether its cleanup finished.
FAQ
What is an AI agent sandbox manifest?
It is a machine-readable contract for an agent run. It declares permitted filesystem mounts, network destinations, credentials, resource limits, output artifacts, and cleanup rules before execution starts.
Is a Docker container enough for an AI coding agent?
Not by itself. You must also control mounts, user privileges, environment variables, forwarded sockets, network egress, credentials, resource limits, and lifecycle cleanup.
Should every AI agent run in a new sandbox?
Use a fresh workspace for tasks that execute code or handle untrusted inputs. Persist state only when the task needs it, and bind that state to an owner, retention limit, and a documented resume path.
How do I give an agent Git access safely?
Issue a short-lived, repository-scoped capability with only the required actions. For example, allow a branch and pull request but require approval before a push or merge. Never forward a personal all-purpose token by default.
What should an agent sandbox log?
Log the manifest digest, input version, image version, capability grants, artifacts, policy denials, result, and cleanup outcome. Redact secrets and avoid retaining private model reasoning or full sensitive command output.
How do sandbox manifests help with cost control?
They define wall-clock, CPU, memory, disk, network, tool-call, and token limits per task. The runtime can enforce those limits even if the agent retries or loops.