Guardrails and Sandboxing for AI Agents
An AI agent becomes risky the moment it can read private data, call tools, write files, send messages, or trigger business workflows. A better prompt helps, but it cannot be the only thing standing between a model mistake and a production side effect.
This guide is for engineers adding tool access to agentic systems. We will secure one refund_order agent by mapping trust boundaries, enforcing tool policies, isolating execution, and designing recovery paths. For related protocol placement, see MCP vs A2A vs ACP.
Map the trust boundaries
A guardrail is useful only when it sits on a real boundary. User text is untrusted. Retrieved documents are untrusted. Model output is untrusted. Tool arguments proposed by the model are untrusted until validated by code. The trusted parts are the runtime, policy engine, identity provider, and the services that own durable state.
For refund_order, the agent may propose { orderId: "123" }, but the payment service still owns whether a refund is allowed. The runtime must check user identity, tenant, order state, amount, idempotency key, and approval requirements before calling the payment provider.
Quick reference
- Separate data boundaries from action boundaries; reading an order is not the same as refunding it.
- Treat retrieved text as hostile input when it can influence a privileged tool call.
- Model output should become a typed request, never direct execution.
- Authority lives in identity and policy checks outside the model.
- Durable systems such as payments, orders, and tickets remain the source of truth.
Remember this
Guardrails belong at boundaries where untrusted text could become privileged action.
Enforce tool policies in code
Tool policy should be explicit: which users can call which tools, with which arguments, under which approval mode, and with which rate limits. Put the rule in code or configuration the model cannot rewrite. The model may explain why it wants a refund; it should not decide alone that the refund is authorized.
For side-effecting tools, use idempotency keys and typed outcomes. A timeout after sending a refund request is an unknown commit state, not a clean failure. Recovery means querying by idempotency key before retrying.
Quick reference
- Validate schema, types, tenant, ownership, and allowed action before execution.
- Split read tools from write tools so approval rules are simpler.
- Return typed denials such as invalid_args, not_authorized, and approval_required.
- Use idempotency keys for every external side effect that can be retried.
- Log redacted arguments and result codes for later eval and incident review.
Remember this
The model may request a tool call; policy code decides whether that call is allowed.
Sandbox what the agent can touch
Sandboxing limits blast radius when a policy misses something. For coding agents, isolate filesystem writes, shell commands, network access, environment variables, and credentials. For browser agents, isolate cookies, sessions, downloads, and domains. For data agents, isolate tenants and make production writes explicit.
A useful sandbox is not only a container. It is the combination of a disposable workspace, scoped credentials, network allowlists, resource limits, and an exit path that captures evidence. If the agent needs broader access, make that access temporary and visible.
Quick reference
- Filesystem: work in a branch or disposable checkout; protect secrets and generated credentials.
- Shell: allow known commands; deny privileged commands and destructive paths by default.
- Network: allow required domains; block arbitrary outbound calls when data is sensitive.
- Credentials: issue scoped tokens per run; rotate or revoke after incidents.
- Resources: cap time, steps, tokens, CPU, memory, and concurrent tool calls.
Remember this
Sandboxing turns one missed instruction into a bounded failed run instead of an unbounded incident.
Design recovery before autonomy
The dangerous failure is not always a dramatic exploit. Often it is ordinary ambiguity: the agent called a payment tool, the provider timed out, and the agent retries with different arguments. Now the system may have two refunds or none, and the trace is too vague to tell.
Recovery should be designed before increasing autonomy. For refund_order, record request IDs, use idempotency keys, query provider status after timeout, keep approval decisions durable, and expose a human review queue for unknown outcomes. The safer agent is not the one that never fails; it is the one whose failures have known terminal states.
Quick reference
- Trigger: timeout after a side-effecting call.
- Symptom: user sees pending or ambiguous result.
- Root mechanism: network failure hides whether the provider committed the action.
- Recovery: query by idempotency key before retrying; escalate if state remains unknown.
- Prevention: typed tool outcomes, approval records, rate limits, and audit logs.
Remember this
Increase autonomy only after every risky tool has a known denial, retry, rollback, or escalation path.
Key takeaway
Guardrails are not one feature. They are layered controls: boundary mapping, policy checks, sandbox limits, traceable decisions, and recovery paths.
Practice (25 min): choose one side-effecting tool in your app. Write its allowed users, denied arguments, approval threshold, idempotency key, timeout behavior, and recovery query. Then simulate a timeout after commit. Pass when the system can detect success without repeating the side effect.
Related Articles
Explore this topic