Quick read · 8 min read
This article shows you how to build guardrails that stop an AI agent from doing real damage before it happens.
Key takeaways
- Sandboxing controls what an AI agent can touch, not just where it runs.
- Every tool an agent uses needs its own limited permission, not one shared key.
- High-impact actions like sending emails need a human approval step before they happen.
- You need a kill switch that stops an agent and undoes its changes within minutes. <!-- omnithium-quick-read:end -->
The operating problem
Your security team just approved an internal agent that drafts customer emails and updates CRM records. It works well in the demo. Then someone asks what happens when a prompt injection hits it. The answer's uncomfortable: the agent runs with a service account that has write access to the CRM, email-send permissions, and a network path to your internal APIs. One bad instruction embedded in a retrieved document, and that agent could send a customer-facing message you never reviewed.
Sandboxing isn't a feature you bolt on after an incident. It's the control plane that determines whether an agent gets to act, what it can touch, and how fast you can revoke that power. Most teams treat sandboxing as container isolation. That's necessary but nowhere near sufficient. A container stops the agent from escaping to the host. It does nothing to stop the agent from calling an overprivileged API, exfiltrating data through an allowed egress path, or sending an email that should have required human approval.
The threat model for agent actions has four distinct failure classes. Prompt injection: an attacker embeds instructions in retrieved content that redirect the agent's behavior. Tool misuse: the agent calls an approved tool with parameters that exceed its intent. Credential exfiltration: the agent reads secrets from its environment and sends them somewhere. Unintended side effects: the agent takes a sequence of individually valid actions that collectively cause harm. Each class needs a different control. Container isolation addresses none of them directly.
The architecture that holds up
You don't choose between process isolation, container isolation, microVM isolation, and cloud-native ephemeral environments. You stack them, and you add policy enforcement at the action boundary, not just the runtime boundary.
Start with the execution layer. Process isolation gives you cheap, fast boundaries within a host, but a compromised process can still read other processes' memory via /proc or ptrace if not configured with seccomp and namespaces. Containers add filesystem and namespace separation, but share the host kernel; a kernel exploit escapes all containers on that host. MicroVMs add a hardware-assisted boundary (e.g., Firecracker, Kata) that makes kernel-level escape dramatically harder, at the cost of 100 to 300 ms cold start and 10 to 20% memory overhead per instance. Cloud-native ephemeral environments (short-lived functions or spot instances) add a time boundary: the runtime disappears after the task, so any compromise has a short shelf life. Choose the isolation tier based on the agent's risk: low-risk internal read-only agents can use containers; high-risk agents that touch customer data or external APIs should use microVMs or ephemeral functions.
But the execution layer is only half the story. The action layer is where the real control happens. Every tool call, every API request, every file read or write passes through a policy engine that evaluates four things: identity, scope, parameters, and risk level. Identity means the agent's service account, not a shared role. Scope means the specific resources that account can touch. Parameters means validating the actual arguments of the call, not just the endpoint. Risk level means whether this action needs human approval before execution. Policy evaluation adds latency; keep it under 10ms per call by caching allowlist decisions and using a local sidecar, not a remote HTTP call for every tool invocation.
Trace an agent action from proposal to execution, showing how identity, policy, and egress controls enforce boundaries at runtime.
The control loop works like this. The agent proposes an action. The policy engine evaluates it against the allowlist, the parameter schema, the rate limits, and the risk classification. If the action is low-risk and within policy, it executes. If it's high-risk, it routes to a human approval gate. If it's outside policy, it's denied and logged. Every decision, every input, every output gets recorded. That audit trail is what makes forensics possible after an incident.
Here's what a policy looks like in practice:
agent: crm-email-agent
service_account: sa-crm-email-7f3a
tools:
crm_update:
endpoint: api.crm.internal/v2/records
methods: [PATCH]
max_records_per_call: 10
requires_approval: false
email_send:
endpoint: api.mail.internal/v1/send
methods: [POST]
requires_approval: true
approval_threshold: external_recipient
network_egress:
allowlist:
- api.crm.internal
- api.mail.internal
default: deny
Credential scoping deserves special attention. Each agent gets its own service account. Tokens are short-lived, scoped to the minimum permissions for that agent's specific tools, and rotated automatically. Use OAuth2 token exchange or SPIFFE/SPIRE for short-lived identity; avoid long-lived static keys. No agent ever inherits a broad IAM role. No agent shares credentials with another agent. When you revoke an agent's access, you revoke one account, not a role that three other agents depend on.
Network egress is the other control point teams overlook. The sandbox should allow outbound connections only to domains on an explicit allowlist. Everything else is denied by default. Enforce egress filtering at the network layer (e.g., eBPF, CNI policy), not just in application code, because a compromised agent can bypass application-level checks. Data loss prevention rules inspect outbound payloads for patterns that match sensitive data. Lateral movement from the sandbox to internal services is blocked unless the policy engine explicitly permits that specific path for that specific agent.
Where teams usually fail
Most failures trace back to three root causes: overprivileged credentials, permissive egress, and missing observability or approval gates.
Overprivileged credentials. An agent runs with a broad IAM role because it was easier to reuse an existing one than to create a scoped service account. Example: an agent that only needs to read one S3 bucket gets s3:* on all buckets. The blast radius is the entire account, not the intended scope. Fix: create a dedicated service account per agent, grant only the exact actions and resources, and use short-lived tokens (15 to 60 minutes) with automatic rotation.
Permissive egress. The tool allowlist says the agent can call the CRM API, but the network egress rules allow any outbound connection. A prompt injection in a retrieved document causes the agent to call http://169.254.169.254/latest/meta-data/iam/security-credentials/ or an attacker-controlled endpoint. The allowlist was enforced at the tool level, not the network level. Fix: default-deny egress at the network layer, allow only explicit domains, and block cloud metadata endpoints (or require IMDSv2 with token).
Missing observability and approval gates. Action logs omit tool parameters or policy decisions, so you can't reconstruct what happened. High-impact actions like sending external emails or deleting records execute without human approval. Fix: log every tool call with full parameters (redact secrets), store immutably, and require approval for any action that modifies external state or exceeds a risk threshold. Approval latency should be p95 < 30 seconds; if it's hours, agents will route around it.
Sandbox escape via shared kernel or mounted volumes is a separate failure; use microVMs for high-risk agents, as described above.
How to measure progress
Measure the metrics that matter during an incident, not quarterly review metrics.
Time to revoke credentials. Target under 5 minutes from detection to revocation. This requires per-agent service accounts and a revocation endpoint that invalidates tokens immediately. If revocation requires a cross-team ticket, you've failed. Test this monthly with a fire drill.
Percentage of tool calls denied by default. This measures whether your allowlist is actually restrictive. If default-deny never fires, your allowlist is too broad. If it fires constantly, your development workflow is too slow. Aim for a stable rate after initial tuning; a sudden spike indicates a new tool or a prompt injection attempt.
Approval gate latency. For high-impact actions, measure p95 time from agent request to human decision. Target under 30 seconds. If approval takes hours, agents will find workarounds. Use a dedicated approval queue with clear context (the exact action, parameters, and risk score) to keep latency low.
Audit trail completeness. Can you reconstruct every action, input, output, and policy decision? Log everything, including tool parameters (with secrets redacted), policy evaluation results, and approval decisions. Store immutably (e.g., append-only object storage) and test queryability under time pressure. If you can't answer "what did the agent do in the last 10 minutes?" within 2 minutes, your logging is insufficient.
What to build next
Start with shadow mode testing. Run the agent against production data with side-effect interception: wrap every tool call in a proxy that logs the intended action and returns a synthetic success response without executing the real side effect. This lets you observe what the agent would have done without letting it do anything. Use this to tune the allowlist and approval thresholds before granting real permissions.
Next, build the kill switch and rollback path. Real-time revocation means terminating the agent's session and revoking its credentials in one operation. Use short-lived tokens (15 to 60 minutes) and a revocation list checked on every tool call. State rollback requires versioned state for every resource the agent can touch (event sourcing or database snapshots). If the agent deletes a record, you need to restore it from the previous version. This isn't glamorous, but it determines whether an incident is a 20-minute containment or a week-long recovery.
Finally, treat sandboxing as a lifecycle concern. Agents move through stages: shadow mode, limited production (read-only or low-risk actions), and full production. Each stage has different policy constraints. Version your policies, test your kill switches, and run incident drills. The goal isn't to prevent every possible failure, but to detect and contain failures quickly.

Top comments (0)