Skip to main content

Agent Security & Sandboxing

Agents change the security problem because they do not just answer questions: they read data, choose tools, run code, and sometimes change production state. Treat an agent as an untrusted program that can be influenced by every token it reads, including tokens from tools, websites, files, email, tickets, logs, and package documentation.

Simon Willison's "lethal trifecta" is the most useful starting model:

  1. Private data access - email, files, repos, databases, tickets, credentials, memory, or user history.
  2. Exposure to untrusted content - web pages, retrieved chunks, issue comments, PDFs, emails, tool results, MCP tool metadata, or third-party agent skills.
  3. External communication - HTTP, email, pull requests, chat messages, image loads, DNS, or any tool that can send data outside the trust boundary.

If one agent has all three, a prompt injection can turn data access into data exfiltration. The goal is not "write a better system prompt." The goal is to break at least one side of the triangle with enforced controls.

For a broader checklist, OWASP publishes two lists: the Top 10 for LLM Applications 2025 (summarized in AI Safety & Guardrails) and the Top 10 for Agentic Applications, released in December 2025, which covers agent-specific risks such as goal and behavior hijacking, tool misuse, identity and privilege abuse, memory poisoning, and cascading failures across multi-agent systems.

Direct and indirect prompt injection

Direct prompt injection is hostile user input in the chat itself. Indirect prompt injection is hostile content that arrives through some other channel and is later placed in the model context. The OWASP LLM01:2025 Prompt Injection write-up explicitly calls out websites and files as indirect sources.

Common indirect sources:

  • Tool outputs - search results, database rows, logs, CI output, shell output, or API responses.
  • Web pages and documents - hidden text, comments, metadata, OCR text, PDF layers, or copied snippets.
  • Email and collaboration tools - an attacker can email the agent's user or file a public issue.
  • Code and package docs - README files, install scripts, examples, and generated changelogs.
  • MCP descriptions and schemas - MCP exposes tool description and inputSchema metadata to the model; the MCP tools spec describes tools as model-controlled and recommends human control over tool invocations.
  • Third-party skills and agent plugins - skill prompts are code-like configuration: review them like dependencies, not like harmless prose.
caution

Everything returned by a tool is untrusted input. Treat it as data, not instruction. The LLM may not keep that distinction reliably once both are concatenated into one context window.

Exfiltration channels to close

Prompt injection becomes an incident when the agent can communicate outward. Block or mediate these channels:

ChannelWhy it mattersControl
Markdown images and linksRendered Markdown can trigger browser fetches or entice clicks; OWASP gives an image-link exfiltration scenario for LLM01Disable remote image rendering, proxy images, strip links from untrusted output, and require safe-link rewriting
Outbound HTTP toolsSearch, webhook, fetch, email, chat, PR, and issue tools can send secrets to an attacker-controlled endpointUse exact host allowlists, method allowlists, request body limits, and approval for data-sharing calls
DNSLookups for attacker-controlled domains can carry data in the hostname, even when direct HTTP is blockedBlock DNS by default, use resolver allowlists, log queries, and run sensitive code in no-network sandboxes
Generated filesThe agent can hide data in commits, artifacts, logs, screenshots, or reportsScan artifacts, review diffs, and separate read-only analysis from publish steps
Cross-tool callsA malicious low-trust tool result can steer a high-trust toolIsolate tool sets by trust domain and prevent low-trust contexts from invoking high-impact tools

Do not rely on the model to avoid these paths. Make the renderer, network layer, and tool runtime enforce the policy.

Excessive agency

OWASP LLM06:2025 Excessive Agency defines the failure mode: too much functionality, too much permission, or too much autonomy. The same prompt injection is far less damaging when the agent can only read a narrow folder than when it can read the whole home directory, post to Slack, create pull requests, and run arbitrary shell commands.

Design tools so the dangerous part is not delegated to the model:

  • Split read tools from write tools.
  • Prefer narrow verbs like createDraftInvoice over generic verbs like runSql or callApi.
  • Bind each tool to a server-side authorization check, not a line in the system prompt.
  • Use dry-run modes and typed diffs before writes.
  • Require human approval for irreversible, external, financial, destructive, or privilege-changing actions.

MCP, skills, and supply chain risk

MCP makes tools composable, but composability increases the supply-chain surface. The MCP security best practices cover authorization pitfalls such as confused-deputy flows and token passthrough. The OWASP MCP Security Cheat Sheet adds practical risks that matter for agents: tool poisoning, rug pulls, over-scoped tokens, untrusted packages, and local MCP servers with host access.

Specific failure modes:

  • Tool poisoning - an MCP server hides instructions in tool descriptions or returns normal-looking data plus hidden instructions. OWASP describes this as an indirect prompt-injection attack against MCP clients; Invariant Labs published an early demonstration.
  • Rug pull after approval - a server changes tool descriptions, schemas, or behavior after the user has already trusted it.
  • Tool shadowing - one server's description tells the model how to misuse another server's trusted tools.
  • Compromised packages - an MCP server, skill, or transitive dependency updates into malware.
  • Credential aggregation - one server receives broad tokens and becomes a high-value target.

Mitigations:

  • Maintain an allowlist of approved servers and skills.
  • Pin package versions and tool-definition hashes; re-prompt when definitions change.
  • Run local servers in separate sandboxes with scoped filesystem and network access.
  • Use short-lived, per-server, least-privilege credentials.
  • Log tool registration, definition changes, and every invocation with parameters redacted for secrets.

Sandboxing options

Sandboxing is defense in depth, not a proof that the agent is safe. Pick the strongest isolation that still allows the job to finish.

Isolation layerUse whenNotes
ContainersYou need repeatable Linux process, filesystem, and cgroup isolationDocker uses namespaces and cgroups; do not mount the Docker socket into an untrusted agent
gVisorYou want stronger-than-container syscall isolation with OCI toolinggVisor's runsc inserts a userspace application kernel between the workload and host kernel
Firecracker microVMsYou need VM boundaries with fast startup and low overheadFirecracker uses KVM microVMs and a jailer for an additional barrier
Dev containersYou need reproducible development environmentsThe Dev Container spec standardizes metadata; it is not by itself a hard security boundary
OS sandboxesYou need local command isolation without a full VMOpenAI documents Codex using macOS Seatbelt and, on Linux/WSL2, bubblewrap plus seccomp; Landlock and seccomp are kernel primitives you can compose in your own runners

Verify the actual product, version, and mode before trusting a sandbox. A label such as "workspace-write" or "sandbox mode" is not enough; check what filesystem writes, network egress, process spawning, and child process inheritance are technically enforced.

Minimal Docker sandbox example

The Docker CLI documents the flags below: --network, --read-only, --cap-drop, --security-opt, --user, --memory, --cpus, and --pids-limit are all current docker run options.

docker run --rm \
--network none \
--read-only \
--cap-drop ALL \
--security-opt no-new-privileges=true \
--user 1000:1000 \
--memory 512m \
--cpus 1 \
--pids-limit 128 \
python:3.13-slim \
python -I -c 'print("hello from a constrained sandbox")'

This example is intentionally narrow: no network, read-only root filesystem, no Linux capabilities, no new privileges, non-root UID/GID, and bounded memory, CPU, and process count. For production, also pin images by digest, scan images, avoid privileged mode, avoid host-path mounts unless they are read-only and scoped, and apply a custom seccomp/AppArmor/SELinux profile where your platform supports it.

Injection-resistant design patterns

The 2025 arXiv paper Design Patterns for Securing LLM Agents against Prompt Injections argues that useful agents can be made safer by constraining what they can do after they ingest untrusted input. The related CaMeL paper, Defeating Prompt Injections by Design, separates trusted control flow from untrusted data flow and uses capabilities to prevent unauthorized exfiltration.

Useful patterns:

  • Action selector - the model selects from a fixed set of pre-approved actions and does not receive feedback that can alter later actions.
  • Plan then execute - create the action plan before reading untrusted data; tool results can fill values but cannot add new steps.
  • Dual LLM - a privileged planner never sees raw untrusted content; a quarantined model extracts facts from that content without tool authority.
  • CaMeL-style mediation - track tainted data and enforce policies when tools are called.
  • Context minimization - remove unneeded user and tool text before later model calls.

These patterns trade generality for security. That is the point: a general-purpose autonomous agent with private data, untrusted input, and egress cannot provide strong prompt-injection guarantees today.

Sandboxed architecture

Key boundaries in the diagram:

  • The privileged planner gets goals and structured facts, not raw hostile pages or emails.
  • The sandboxed executor owns side effects and runs under OS, filesystem, network, and resource limits.
  • Secrets are fetched just in time by tools, not pasted into the context window.
  • Egress is mediated outside the model.
  • Logs capture decisions, tool calls, approvals, and denied actions.

Practical checklist

Use this before giving an agent new tools or data:

  • Identify the trust boundary for every input source: user, web, email, repo, RAG, MCP, logs, and tools.
  • Decide which side of the lethal trifecta you are breaking: data access, untrusted input, or egress.
  • Remove secrets from prompts, chat history, retrieval chunks, screenshots, and logs.
  • Use short-lived, scoped credentials per tool and per server.
  • Scope filesystem access to the smallest workspace; prefer read-only mounts for analysis.
  • Disable network by default; allow exact hosts, methods, ports, and protocols only when required.
  • Block or proxy Markdown images and untrusted links in model-rendered output.
  • Split read tools from write tools and high-trust tools from low-trust tools.
  • Require approval for destructive, irreversible, financial, external-sharing, or privilege-changing calls.
  • Pin MCP servers, skills, package versions, and tool-definition hashes.
  • Re-review tools when descriptions, schemas, scopes, or publishers change.
  • Validate tool inputs and outputs with schemas; reject extra fields and unexpected free text.
  • Run code execution in containers, gVisor, microVMs, or OS sandboxes with resource limits.
  • Log prompts, tool calls, approvals, denials, egress, and artifact publication with secret redaction.
  • Red-team direct and indirect prompt injection paths before enabling autonomous operation.

See also