Sandboxing Code-Executing Agents: Container Isolation, Seccomp, and Egress Allowlists
TL;DR: Code-executing agents turn model output into running processes, so the sandbox becomes part of your threat model. Combine three layers — locked-down containers, a restrictive
seccompprofile, and an egress allowlist — with a policy decision point that sits before any provider or tool call. Add delegated identity, just-in-time credentials, approval checkpoints, fail-closed defaults, and an audit trail, and you have a practical ai agent security infrastructure baseline you can build and test incrementally.
AI agents that write and run code — a data-analysis agent executing Python, a DevOps agent running kubectl, an research agent invoking scripts — move risk from “bad output” to “bad execution.” The model’s generated code runs with real syscalls, real network access, and often real credentials. This tutorial walks you through a layered sandbox design: container isolation, seccomp filtering, and egress allowlists, then wraps them in the identity, policy, and audit controls that make the system operable in production.
What You Will Learn
- How to map the real attack surface of a code-executing agent, from identity to multi-step execution.
- How to build a reference architecture where a policy boundary sits before every provider and tool call.
- How to configure container isolation, a custom
seccompprofile, and DNS/IP egress allowlists with runnable examples. - How to add delegated identity, JIT credentials, approval checkpoints, and fail-closed behavior.
- How to test, monitor, and document your controls for audit and incident response.
Table of Contents
- Map the Agent Attack Surface
- Reference Architecture for AI Agent Security Infrastructure
- Step 1: Container Isolation
- Step 2: Seccomp and Kernel Hardening
- Step 3: Egress Allowlists
- Step 4: Identity, JIT Credentials, and Approvals
- Testing and Monitoring the Sandbox
- Governance, Audit Evidence, and Incident Response
- FAQ
- Further Reading
Map the Agent Attack Surface
Before writing configuration, enumerate what an attacker (or a hallucinating model) can reach. Treat each item as a control surface:
- Identity — Is the agent acting as itself, or as a shared service account that also runs your batch jobs?
- Prompts and memory — Injected instructions in retrieved documents or tool results can redirect execution.
- Tools and connectors — Every MCP server, browser tool, or database connector widens the callable surface.
- Credentials — Long-lived keys in environment variables are the most common failure.
- Data — Generated code can read files inside the sandbox, including anything mounted in.
- Network egress — Unrestricted outbound access enables data exfiltration and package-install supply-chain attacks.
- Multi-step execution — An agent that loops over steps can chain individually harmless actions into a harmful sequence.
The key insight: hardening only the container addresses items 5 and 6. Identity, credentials, and policy must be handled outside the runtime — which leads to the architecture.
Reference Architecture for AI Agent Security Infrastructure
The pattern that scales is a governed gateway — an authorization and policy boundary between the agent runtime and everything external.
[Human user]
|
v
[Agent runtime] --> [Policy gateway] --> [LLM provider]
sandboxed allow/deny/approve [Tools / MCP / APIs]
no long-lived scoped grants [Cloud (e.g. AWS)]
credentials evidence log [Databases]
Rules of the road:
- The agent holds no long-lived credentials. It requests capability; the gateway decides.
- Each request carries a distinct agent identity bound to the requesting human, so accountability survives delegation.
- Grants are exact and resource-bound: “read
s3://reports/2026/*for 15 minutes,” nots3:*. - The gateway returns allow, deny, or require scoped human approval — never silent fallback.
- Every decision and result writes to a linked evidence trail.
This is the same principle behind an ai agent security gateway: policy is evaluated before provider access, not after. Commercial offerings differ in features, so verify current capabilities against primary vendor documentation rather than assuming parity. With the boundary defined, we can harden what runs behind it.
Step 1: Container Isolation
Start by removing every privilege the agent does not need. A useful baseline for a code-executing agent:
# docker-compose.agent.yml
services:
agent-sandbox:
image: agent-runtime:1.4
read_only: true
user: "10001:10001"
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /tmp:size=64m,noexec,nosuid
volumes:
- ./workspace:/workspace:rw # only the agent's own scratch dir
pids_limit: 256
mem_limit: 1g
cpus: 1.0
networks:
- sandbox-net # isolated network; egress filtered separately
Key decisions:
- Never mount the Docker socket, host SSH keys, or
~/.aws. If the agent needs cloud access, it gets a short-lived, scoped credential injected at request time — not a mounted profile. read_only+tmpfsprevents persistence across runs.cap_drop: ALLremoves capabilities such asSYS_ADMINthat enable container escapes.- One workspace directory limits blast radius when generated code goes wrong.
For stronger guarantees, run each session in a microVM (Firecracker, Cloud Hypervisor) or a gVisor/Kata runtime when the workload is untrusted enough to justify the overhead. Containers are a strong baseline, not a perfect boundary.
Step 2: Seccomp and Kernel Hardening
seccomp filters which syscalls a process may make. Docker and containerd ship a default profile; for agents, start from it and deny aggressively.
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": ["read", "write", "exit", "exit_group", "brk", "mmap",
"futex", "clock_gettime", "openat", "stat", "fcntl"],
"action": "SCMP_ACT_ALLOW"
}
]
}
In practice you will iterate: run your agent’s test suite, log EPERM failures, and allow only what legitimate workloads require. Deny by default on these high-risk families:
| Syscall family | Why it is dangerous |
|---|---|
mount, umount2, pivot_root |
Filesystem manipulation, escape attempts |
ptrace, process_vm_readv |
Read other processes’ memory |
keyctl, add_key |
Kernel keyring access |
clone with unusual flags |
Namespace manipulation |
bpf |
Load eBPF programs |
Apply it and harden the kernel surface:
docker run --security-opt seccomp=agent-seccomp.json \
--security-opt no-new-privileges=true \
--cap-drop=ALL agent-runtime:1.4 python analyze.py
Also disable unused kernel features at the host level (unprivileged_userns_clone=0 where your distro allows it), keep the host patched, and separate agent hosts from CI and production workloads. Kernel hardening only helps if you patch — which is why monitoring comes later.
Step 3: Egress Allowlists
Unfiltered outbound network access negates most of the work above: generated code can exfiltrate data, pip install from a typosquatted package, or reach metadata endpoints.
Deny by default, then allow only what the task requires:
# Example egress policy (expressed as policy, implement with
# gateway, proxy, iptables/ebpf, or a service mesh)
egress:
default: deny
allow:
- host: api.openai.com
port: 443
purpose: LLM provider via gateway
- host: pypi.org
port: 443
purpose: approved package mirror
- host: internal-artifact.corp.example
port: 443
purpose: internal libraries
deny_explicit:
- 169.254.169.254 # cloud metadata service
- "*.duckdns.org" # common exfil channels
Practical notes:
- Block cloud metadata endpoints (
169.254.169.254, and IMDSv2 enforced at the account level) — this is a core aws ai agent security control when agents run near AWS resources. - Proxy through a logging egress gateway so every destination is recorded and attributable.
- Pin packages to an internal mirror instead of the public internet; a permissive
pip installis an unreviewed code-execution path. - Prefer FQDN allowlists with TLS inspection at your own proxy over raw IP lists, since IPs rotate.
With isolation, syscalls, and network locked down, the remaining gap is who the agent is allowed to act as.
Step 4: Identity, JIT Credentials, and Approvals
Sandboxing constrains what code can do; identity constrains what the agent is allowed to do. Combine them:
# Pseudocode: policy decision before any tool or provider call
def handle_tool_call(agent, request, human_principal):
identity = bind_identity(agent.id, human_principal) # agent != shared svc acct
grant = issue_jit_credential( # seconds-to-minutes TTL
identity=identity,
scope=request.required_scope, # exact resources
resource=request.target, # resource-bound
)
decision = policy.evaluate(identity, request)
if decision.action == "deny":
audit.log(identity, request, "denied", decision.reason)
return Denied(decision.reason)
if decision.action == "require_approval":
audit.log(identity, request, "pending")
if not wait_for_human_approval(request, timeout="10m"):
return Denied("approval timeout") # fail closed
return execute_with(grant, request)
Non-negotiable behaviors:
- Least privilege: scopes are derived from the task, not a fixed broad role.
- JIT credentials: minted at call time, expired automatically, never written to disk or agent memory.
- Approval checkpoints: destructive or high-blast-radius actions (prod deploy, payment, bulk export) pause for scoped human sign-off.
- Fail closed: gateway unreachable, policy store stale, or approval timed out → deny, and surface why.
- Revocation without redeploy: killing a delegated grant takes effect immediately, even while the agent process keeps running.
This separation also means rotating or revoking authority does not require rebuilding the agent image — a common failure in credential-in-image setups.
Testing and Monitoring the Sandbox
A control you have not tested is an assumption. Build a small adversarial suite:
# 1. Verify the seccomp profile actually blocks high-risk syscalls
docker run --security-opt seccomp=agent-seccomp.json agent-runtime:1.4 \
python -c "import ctypes; ctypes.CDLL(None).prctl(22, 0)" # expect EPERM
# 2. Verify egress default-deny
docker exec sandbox curl -s --max-time 5 https://example.com && echo "FAIL: open egress"
# 3. Verify no metadata access (run inside an AWS workload)
docker exec sandbox curl -s --max-time 3 http://169.254.169.254/ && echo "FAIL: IMDS reachable"
# 4. Verify fail-closed: stop the policy gateway, re-run a tool call
# Expected result: Denied, not silently executed
Monitor continuously:
- Egress logs: alert on first-seen destinations, not just known-bad ones.
- Policy decisions: count denies and approval-override rates by agent and human principal.
- Credential lifetimes: alert if any credential outlives its TTL.
- Anomalous tool sequences: a single step may be legitimate; the chain may not be.
Ship these as CI checks so a misconfiguration (a dropped cap_drop, an accidentally allow-all egress rule) fails the build instead of reaching production.
Governance, Audit Evidence, and Incident Response
Technical controls need operational scaffolding:
- Evidence trail: log identity, request, policy decision, approver, credential scope, and outcome as one linked record per action. This is what makes post-incident review and internal audit tractable.
- Data classification: decide which data classes may enter a sandbox at all; some should never be exposed to code generation.
- Incident playbook: define revocation steps (kill delegated grants, rotate gateway keys, isolate agent hosts) before you need them. Practice that revocation works without redeploying.
- Regulated industries: map each control to your own obligations (access review, retention, separation of duties) and confirm with your compliance team. Controls support evidence collection; they do not by themselves confer any certification or legal guarantee.
- Cloud context: if workloads run on AWS, combine sandbox controls with IAM conditions, IMDSv2 enforcement, VPC egress controls, and centralized logging — and always check current AWS documentation for the latest guidance rather than relying on secondhand summaries.
With controls, tests, and evidence in place, you have a defensible baseline — and a clear backlog of the next risks to reduce.
Conclusion
Sandboxing a code-executing agent is not one setting but a stack: container isolation limits what the process can touch, seccomp limits which syscalls it can make, and egress allowlists limit where it can send data. Wrapped around that runtime, ai agent security infrastructure adds the pieces a sandbox alone cannot provide — distinct identity bound to a human, delegated and resource-bound grants, just-in-time credentials, approval checkpoints, fail-closed defaults, and a linked evidence trail. Build it in that order: isolate, filter, constrain the network, then govern identity and prove it with tests. Each layer reduces a different failure mode, and together they turn an agent that can execute code into one you can safely let execute code.
FAQ
1. Why isn’t a Docker container enough to secure a code-executing AI agent?
Containers share the host kernel and often run with permissive defaults. Without seccomp, dropped capabilities, resource limits, and network restrictions, generated code can probe the host, exhaust resources, or exfiltrate data. The container is one layer, not the boundary.
2. What is an ai agent security gateway and where does it sit? It is an authorization and policy layer between the agent runtime and LLM providers, tools, and APIs. Every call is evaluated for allow, deny, or human approval before it leaves the agent, and credentials are issued just-in-time rather than stored in the runtime.
3. How do I stop an agent from exfiltrating data over the network? Default-deny egress with an explicit allowlist of required hosts, enforced by a logging proxy or network policy. Block cloud metadata endpoints, pin packages to an internal mirror, and log every destination for review.
4. What does least privilege mean for agent credentials? Issue short-lived credentials scoped to the exact resources a single step requires — for example, read access to one bucket prefix for 15 minutes — instead of a standing role. Revoke the grant without redeploying the agent when the task ends.
5. How does aws ai agent security differ from sandbox hardening? Sandbox hardening governs what code can do at runtime. AWS-side controls govern where it runs and what it can reach: IAM conditions, IMDSv2, VPC and egress controls, and centralized logging. You need both; neither substitutes for the other.
Further Reading
- NIST SP 800-190 — Application Container Security Guide — the foundational reference for container threat modeling, image security, and runtime hardening.
- Docker Security — Seccomp in Docker — official documentation on writing and applying custom
seccompprofiles. - OWASP AI Security and Privacy Guide — broader guidance on securing AI systems, including agent-specific risks and governance practices.
Want a second set of eyes on your architecture? If you are designing sandboxing, identity, or policy controls for your agents, we are happy to walk through your ai agent security infrastructure with you — no pitch required. Book a 30-minute conversation: https://cal.id/axec/demo?duration=30