We use cookies to enhance user experience, personalize content, and analyze traffic. Cookie Policy

← Back to all articles

AI Agent Security: Prompt Injection, Sandboxes, and Egress

AI agent security in practice: why prompt injection can't be filtered away, how to sandbox agent code, and how to lock network egress so leaks fail.

by Unknown Proxies

16 min read

October 31, 2026

AI Agent Security: Prompt Injection, Sandboxes, and Egress

AI agent security comes down to one assumption: anything the model reads can tell it what to do. Prompt injection has no reliable fix at the model level in 2026, so you can't make an agent safe by asking it to ignore bad instructions. You make it safe by limiting what a hijacked agent can reach. That means scoped tools and credentials, a sandbox around any code it runs, a human confirmation before irreversible actions, and a network path that only goes where the task needs.

The network layer is the one teams skip, and it is the one that turns a successful injection into a failed one. An agent that reads a poisoned page and then tries to send your API key to attacker.example only leaks something if that request can leave the machine. We tested common exfiltration routes against three sandbox setups on a cloud server. With only proxy environment variables set, the agent reached an off-list site, the cloud metadata service, and arbitrary DNS just by not using the proxy. An internal Docker network behind an allowlisting proxy blocked all of those. The one leak it couldn't stop was a POST to a domain on the allowlist, which no domain allowlist can stop.

This guide covers the threat model, prompt injection defenses that hold up, how to pick a sandbox, and the egress setup we tested, with configs you can copy.

The AI agent security threat model

An agent is a loop: the model reads context, picks a tool, your code runs it, and the result goes back into context. Every tool result is input the model will reason over. That includes web pages, emails, PDFs, issue comments, search snippets, and the output of other agents. None of that text is trusted, and the model has no way to tell your instructions from someone else's.

Simon Willison calls the dangerous combination the lethal trifecta. An agent becomes exploitable when it has all three of:

  1. Access to private data, such as your inbox, a database, or environment variables
  2. Exposure to untrusted content, such as web pages or inbound email
  3. A way to communicate externally, such as an HTTP tool, a browser, or even a rendered image URL

Meta's Agents Rule of Two turns that into a design rule. Within one session, an agent should have at most two of these: processing untrustworthy input, access to sensitive systems or private data, and the ability to change state or communicate externally. If a task needs all three, Meta's guidance is that the agent shouldn't run autonomously and needs at least human-in-the-loop approval.

Before and after view of the lethal trifecta, where private data, untrusted content, and outbound communication overlap in a red exploitable zone until the outbound leg is cut away and the overlap turns grey

Most real agents need private data and untrusted content to be useful. The leg you can usually cut, or at least narrow to a few destinations, is outbound communication. That is why the egress section below gets the most space.

OWASP's Top 10 for Agentic Applications, published in December 2025, catalogs the wider set. Its first entry, ASI01 Agent Goal Hijack, is prompt injection seen from the agent's side. Several of the others, such as tool misuse, identity and privilege abuse, and unexpected code execution, describe what a hijacked agent does next. This table maps the threats you'll run into first to the control that addresses each one.

Threat How it shows up in an agent Primary control
Goal hijack via prompt injection A page, email, or tool output tells the agent to do something else Treat all tool output as untrusted; gate actions in code
Tool misuse The agent calls a legitimate tool with harmful arguments, such as DELETE or a transfer Narrow tools, argument validation, confirmations
Credential exposure Secrets in the prompt, environment, or files the agent can read Keep credentials outside the sandbox, scoped tokens
Code execution escape Generated code reads the host, other tenants, or cloud metadata Sandbox with its own kernel or a user-space kernel
Data exfiltration Secrets leave through HTTP, DNS, image URLs, or an allowed domain Default-deny egress through an allowlisting proxy
Supply chain A malicious MCP server, package, or tool description Pin and review tools; least privilege per server

Why prompt injection can't be filtered out

Direct prompt injection is the user typing "ignore your instructions." Indirect prompt injection is the version that matters for agents: the instruction arrives inside data the agent fetched. OWASP ranks it first as LLM01: Prompt Injection. Our agentic browser guide walks through a real case against a logged-in AI browser.

Three things make it hard to stop:

The defenses that hold up don't rely on the model noticing the attack. They change what the model is able to do after reading untrusted text. Design Patterns for Securing LLM Agents against Prompt Injections (Beurer-Kellner et al., 2025) describes six such patterns, including Plan-Then-Execute, Dual LLM, and Context-Minimization. CaMeL (Debenedetti et al., 2025) goes further. A privileged model writes a program from the trusted request, and a quarantined model that reads untrusted data can't add new steps to it.

In practice, most teams combine a few cheap controls:

Least privilege for agent tools and credentials

Every tool you register is a capability an attacker can borrow. Scope each one to the task, not to what is convenient.

The same rule applies to proxy credentials. If a browser agent needs a proxy, keep the password in a forwarder the agent can't read, not in its environment. The Puppeteer MCP proxy guide shows why: its navigate tool accepts launch options from the model, which can replace or switch off the proxy you configured.

Sandboxing AI agent code execution

If the agent runs code, whether that is generated Python, shell commands, or a headless browser, run it somewhere you can throw away. The choice is mostly about how much kernel the sandbox shares with your host.

Three AI agent sandbox types side by side, where an attack from a container reaches the shared host kernel, a gVisor user-space kernel stops it above the host, and a microVM stops it at its own guest kernel

Sandbox Isolation boundary Cost Good fit
Plain Docker or Podman container Namespaces and cgroups on the shared host kernel Lowest Your own agents running your own tasks, plus the network controls below
Process sandbox: bubblewrap, Landlock, seccomp, macOS Seatbelt Kernel restrictions on one process tree Lowest Coding agents on a developer machine
gVisor (runsc) A user-space kernel handles the container's syscalls Slower syscalls and file I/O Running untrusted code on shared hosts
Firecracker or other microVMs A separate guest kernel on KVM A VM per sandbox, though Firecracker advertises boot in under 125 ms Multi-tenant code execution, hosted agent sandboxes

Coding agents already ship with the process sandbox row. Claude Code's sandbox uses bubblewrap on Linux and Seatbelt on macOS, and its runtime is open source as sandbox-runtime. OpenAI's Codex sandbox uses Seatbelt on macOS and bubblewrap plus seccomp on Linux, with network access off by default in its workspace-write mode. For hosted code execution, gVisor and Firecracker are the common building blocks. E2B, for example, runs one Firecracker microVM per sandbox.

Whichever you pick, apply the same hardening:

A sandbox limits what code can touch on the machine. By itself, it does nothing about where that code can send data. A default Docker container can reach the whole internet and, on many clouds, the instance metadata service.

Network isolation: the control injection can't talk past

Egress control is the part of AI agent security that works the same no matter how clever the injected text is. If the sandbox has no route to a destination, nothing the model writes can reach it.

We tested this on a Hetzner Cloud VM in Nuremberg running Docker Engine 29.1.3, using curlimages/curl (curl 8.22.0) as the stand-in for an agent's tools. The allowlisting proxy was Squid from the ubuntu/squid image, configured to allow only example.com and httpbin.org. We compared three setups:

AI agent sandbox on an internal Docker network whose only route out is an allowlisting egress proxy, with direct internet, DNS, and cloud metadata paths blocked and allowed traffic forwarded to an upstream proxy

Here is what each probe returned:

Probe from inside the sandbox A: env vars only B: internal network + Squid C: --unshare-net
HTTPS to allowlisted example.com 200 200 Could not resolve host
HTTPS to off-list www.wikipedia.org 403 on CONNECT 403 on CONNECT Could not resolve host
Same request with --noproxy '*' 200, leaked Could not resolve host Could not resolve host
Plain HTTP to the metadata service, uppercase HTTP_PROXY set Returned the VM hostname Connection failed Connection failed
Same, with lowercase http_proxy 403 from Squid 403 from Squid Not applicable
DNS lookup of an external name Resolved SERVFAIL Could not resolve
Raw TCP to 1.1.1.1:443 Connected Failed Network unreachable
CONNECT 1.1.1.1:443 through the proxy 403 403 Not applicable
POST with a secret to allowlisted httpbin.org 200, leaked 200, leaked Could not resolve host

Four findings matter for anyone building agents.

Proxy environment variables are a suggestion, not a boundary. In setup A, the agent ignored the proxy with one flag and reached an off-list site. Any shell tool, any pip install, or any library that doesn't read proxy variables goes straight out. The container's network decides what is reachable, and the env vars only decide what is polite.

Uppercase HTTP_PROXY is silently ignored by curl. curl accepts only the lowercase http_proxy for plain HTTP, a defense against the httpoxy header attack, while it accepts either case for HTTPS_PROXY. With only uppercase variables set, our plain-HTTP request to the metadata service skipped Squid and returned the VM's hostname. Set both cases, and don't treat either as enforcement.

The metadata service is worth a probe of its own. On Hetzner Cloud, the metadata service exposes the hostname, public IPv4, and private networks. On AWS, IMDSv1 hands the instance role's temporary credentials to any process that asks. IMDSv2 requires a session token whose response hop limit defaults to 1, which keeps it away from most bridged containers, but AWS suggests raising the limit to 2 for container workloads. A sandbox on an internal network can't reach the metadata address no matter how the instance is configured.

DNS is an exfiltration path, and an internal network closes it. A query for <secret>.attacker.example reaches the authoritative name server for attacker.example even when every HTTP request is blocked, so the attacker reads the secret from their DNS logs. In setup A, the container resolved external names normally. On the --internal network, Docker's embedded resolver at 127.0.0.11 returned SERVFAIL for both external names we tried, so the agent couldn't resolve or leak through DNS. That is deliberate. Since Engine 26.0, Docker doesn't forward external DNS queries for containers attached only to internal networks, a fix aimed at exactly this exfiltration path. On older engines whose host resolver listens on loopback, such as systemd-resolved at 127.0.0.53, or for a container that is also attached to a normal network, DNS still gets out. The agent didn't need DNS anyway: with an HTTP proxy, the proxy resolves hostnames.

A domain allowlist can't stop writes to an allowed domain. Squid logged the exfiltration POST as a TCP_TUNNEL/200 entry for CONNECT httpbin.org:443, nothing more. For HTTPS, a forward proxy sees only the host and port in CONNECT, not the method, path, or body. Squid's HTTPS documentation says as much: without SslBump decryption, it has no access to the encrypted messages. So an allowlist is only as safe as the least trustworthy domain on it. github.com, pastebin.com, any webhook service, and any object storage bucket accept writes from anyone with an account, and an injected agent can create one. Claude Code's sandbox docs give the same warning about github.com. They add that because the proxy decides from the client-supplied hostname without inspecting TLS, sandboxed code could use domain fronting to reach hosts outside the allowlist. The same applies to Squid without SslBump.

Egress proxy config for AI agents

This is the Squid config from setup B. dstdomain entries that start with a dot match the domain and its subdomains:

http_port 3128

acl allowed_sites dstdomain .example.com httpbin.org
acl SSL_ports port 443
acl CONNECT method CONNECT

http_access deny CONNECT !SSL_ports
http_access allow allowed_sites
http_access deny all

cache deny all
access_log stdio:/var/log/squid/access.log

If the agent only drives a browser, the computer use agents guide covers a lighter variant that locks the browser to a credential-holding GOST forwarder. For agents with a shell or code execution, wire up the networks so the proxy is the only route:

docker network create --internal agent-net
docker network create egress-net

docker run -d --name egress --network egress-net \
  -v "$PWD/squid.conf:/etc/squid/squid.conf:ro" ubuntu/squid:latest
docker network connect agent-net egress

docker run --rm --network agent-net \
  -e HTTPS_PROXY=http://egress:3128 -e https_proxy=http://egress:3128 \
  -e HTTP_PROXY=http://egress:3128 -e http_proxy=http://egress:3128 \
  your-agent-image

Then check it the way an attacker would. From inside the agent container, run curl --noproxy '*' https://example.org, nslookup example.org, curl --noproxy '*' https://1.1.1.1, and curl --noproxy '*' http://169.254.169.254/. All four should fail. The 1.1.1.1 probe matters because it skips DNS: a container that can't resolve names may still have a direct route to any IP. If any of them succeed, the container has a route out that isn't the proxy.

Keep the allowlist per task, not per company. A research agent needs search and a few documentation sites. A coding agent needs your package registry and your Git host, ideally a mirror you control rather than all of github.com. Review access.log after real runs, because the TCP_DENIED lines show you what the agent tried to reach.

Keep proxy credentials out of the sandbox

Some agents need a specific exit IP: a stable address an internal API allowlists, a country for geo-specific results, or an IP that isn't your cloud provider's range. Point Squid at an upstream proxy with cache_peer, and the credentials live only in the egress container:

cache_peer proxy.example.net parent 8080 0 no-query no-digest login=AGENT_USER:AGENT_PASS name=upstream
never_direct allow all

We ran this against a test upstream that required Basic auth. The allowed request was logged as FIRSTUP_PARENT and arrived at the upstream with valid Proxy-Authorization. The off-list request was still refused by Squid before it reached the upstream. The agent container had no copy of the credentials and no route to the upstream: connecting to it by name failed because the internal network couldn't resolve it. never_direct allow all matters here. Without it, Squid can fall back to connecting directly when the parent is down, and your agent's traffic leaves from the server's own IP.

This is where ISP proxies and residential proxies fit into an agent stack. They give each agent a deliberate exit identity, separate from the server that holds your databases and keys. Use one proxy user per agent so you can rotate one without touching the rest, and a static ISP IP when the agent logs in to the same accounts every day. A proxy doesn't make an agent harder to inject, and it won't protect a domain you allowlisted. It does keep your infrastructure's IP out of the agent's traffic and gives you a second log of every host it reached.

AI agent security checklist

Before an agent touches real data, check that:

  1. Every tool result, page, and file is treated as untrusted input, including output from other agents.
  2. Sends, payments, deletions, and permission changes need a human confirmation enforced in code.
  3. Each agent has its own scoped, expiring credentials, and none of them appear in the prompt.
  4. Generated code runs in a disposable sandbox as a non-root user with no host mounts.
  5. The sandbox's only route out is an allowlisting proxy, and direct, DNS, and metadata probes fail.
  6. The allowlist contains no domain where anyone can write: no pastebins, webhook services, or entire code hosts.
  7. Proxy and API credentials live outside the sandbox, in the forwarder or the tool layer.
  8. You log tool calls and egress, and someone reviews denied requests after real runs.

FAQ

What is AI agent security?

It's the practice of limiting what an LLM-driven agent can read, run, and send, so that a manipulated agent can't cause real damage. Since prompt injection isn't solved, the controls sit outside the model: least-privilege tools, sandboxes for code, human confirmations, and restricted network egress.

Can prompt injection be fully prevented?

Not with current models. Classifiers and careful prompts reduce the success rate, but none of them guarantee that a model will ignore instructions hidden in content it reads. Design so a successful injection has nothing valuable to reach and no way to send data out.

Is a Docker container a secure sandbox for an AI agent?

It's a reasonable boundary for code you mostly trust, as long as you drop capabilities, run as non-root, and lock the network. For untrusted code from many users, add a stronger boundary such as gVisor or a microVM, because a container shares the host kernel.

Do AI agents need network isolation if they run in a sandbox?

Yes. A sandbox controls the filesystem and processes, not where data goes. In our test, a default container reached the open internet, resolved arbitrary DNS names, and read the cloud metadata service. An internal network behind an allowlisting proxy blocked all three.

Does a proxy make an AI agent secure?

No. A proxy is useful as the enforcement point for an egress allowlist and as a way to give an agent a separate exit IP. It can't stop the model from following injected instructions, and it can't inspect what an agent sends to an allowed HTTPS domain without TLS interception.

Final thoughts

AI agent security works when you stop expecting the model to defend itself. Assume an injected instruction will eventually get through, then make sure it lands in a sandbox with scoped credentials, a human gate in front of anything irreversible, and a network that only reaches the handful of hosts the task needs.

Start with egress, because it is cheap and you can test it in five minutes. Put the agent on an internal network, route it through an allowlisting proxy, and run the direct, DNS, and metadata probes yourself. If your agents also need a stable or country-specific exit IP, point that proxy at a dedicated upstream. ISP plans give each agent a static address, and residential proxies cover country-targeted sessions.

About the Author

Unknown Proxies

Proxy Infrastructure Team

Stay Unknown

High-performance dedicated proxies optimized for speed and reliability. Get uncompromising quality, 99.9% uptime, and unmatched support. Stay Unknown.

Explore Plans