Egress Control for AI Agents: Stop Your Agent Reaching What It Should Not
AI Security · practitioner · 10 min read · last reviewed 2026-08-23
Default-deny egress at a proxy the agent cannot route around is the highest-leverage single control for agent security. An allowlist alone will not stop exfiltration.
TL;DR
- Egress control for an AI agent means the agent can reach nothing until you explicitly allow it, enforced at a proxy the agent cannot route around.
- The forward proxy is the only chokepoint that sees every outbound request, MCP tool call, and WebSocket frame, and the only one an agent that writes its own code cannot argue with.
- Build the allowlist from observed traffic in log-only mode rather than from imagination, and treat model APIs, tool APIs, and package registries as three separate risk categories.
- An allowlist alone does not stop exfiltration: an injected agent can carry data out through a free-text field of a service you already permitted, so the request body has to be inspected too.
- MCP tool servers make their own outbound connections, so egress control scoped to the agent process leaves a gate in the fence. Proxy the tool servers under the same default-deny policy.
Egress control for an AI agent means the agent can reach nothing on the network until you explicitly allow it, enforced at a proxy the agent cannot route around. It is the single highest-leverage control for agent security, and the reason is structural: the agent decides at runtime what to call, so the boundary has to sit outside the agent.
What is egress control for an AI agent?
Egress is outbound traffic. Egress control is deciding what outbound traffic is permitted, and enforcing that decision somewhere the workload cannot bypass.
For ordinary software this is a familiar hygiene control. For an AI agent it is different in kind, because of what an agent is: a program that chooses its own next action, including which network calls to make. Over a single task, an agent might call a model API, invoke tools over the Model Context Protocol (MCP), fetch arbitrary web pages, install a package, and hold open a WebSocket. Every one of those is an outbound connection, and every one is a path for data to leave.
You cannot enumerate an agent's destinations in advance the way you can for a normal service. So you invert the question: instead of listing what it must not reach, list what it may.
Why the proxy is the right chokepoint
The forward proxy is the only place in the stack that sees all of an agent's outbound traffic, and it is the only place the agent cannot argue with.
Framework-level controls are easier to add and weaker in kind. A tool allowlist inside your agent framework, a hook that checks URLs before a fetch, a system prompt telling the model not to call certain services: each of these is a request to a system that generates and runs its own code. If the agent can execute a shell command, it can open a socket. If it can install a package, it can install one that makes network calls for it.
A proxy the traffic must physically traverse is a boundary. The agent does not have to cooperate, does not have to be aware it exists, and cannot decide to skip it. Enforce it at the network level: the workload's network namespace has no route out except through the proxy.
Keep the framework controls too. They give better error messages and catch mistakes earlier. Just do not mistake them for the boundary.
Building the allowlist
Start from deny-all. Everything else in this section is about what you add back.
Build the list from observed traffic, not from imagination. Run the agent against real tasks with the proxy in log-only mode, collect the destinations it actually uses, then convert that list into policy and switch to enforcing. Guessing produces a list that is simultaneously too permissive and missing the things that break in production.
Treat these as three separate categories, because their risk profiles genuinely differ:
| Category | Examples | Why it is different |
|---|---|---|
| Model APIs | The provider endpoints your agent infers against | High volume, high trust, and every prompt and response passes through. The place where the most sensitive content flows. |
| Tool and data APIs | Your issue tracker, CRM, internal services, third-party APIs | Where an injected agent can act with your credentials. Also the most likely exfiltration channel, because these accept free-form text. |
| Package and artifact registries | npm, PyPI, container registries | Should usually be reachable only during a build, not at agent runtime. If your agent installs packages while it works, that is a supply-chain decision you have made by accident. |
Two rules that save trouble later. Pin to hostnames rather than IP addresses, because cloud services move. And keep the allowlist in version control next to the agent's code, so a new destination is a reviewed change rather than a console click nobody remembers.
Why an allowlist alone is not enough
This is the part most published guidance misses, and it is the reason a "we allowlist our agent's destinations" answer should not end the conversation.
An attacker who achieves prompt injection does not need to reach an attacker-controlled server.
They can put the data in a destination you already allowed. A comment on your own issue tracker. A message in your own chat workspace. A field in your own CRM. A commit message. A support ticket. The destination is on the list, the request is permitted by policy, and the data has left the building.
Every one of those services is on your allowlist for a good reason, and every one of them accepts free-form text. That combination is the exfiltration channel, and no destination-based policy can see it, because from the network's point of view nothing unusual happened.
Closing the gap requires inspecting the request body, not just the destination:
- Credential patterns. API keys, tokens, private keys, and connection strings leaving in a request body are almost never legitimate.
- Encodings that hide payloads. Base64 and hex blobs inside a field that should hold a sentence.
- Volume anomalies. A tool call that normally carries 200 characters suddenly carrying 200 kilobytes is worth stopping and asking about.
This is where an agent egress proxy differs from a firewall. A firewall decides whether the connection is permitted. An egress proxy for agents decides whether this particular request is permitted, which requires reading it.
That means you are inspecting content, so the same governance obligations from TLS inspection apply here: decide what you log, for how long, and who can read it. The difference is that agent traffic is machine traffic rather than an employee's browsing, which usually makes the privacy calculus much easier.
Watch the MCP path specifically
Here is a hole that catches teams who believe they are covered.
MCP server traffic frequently bypasses an allowlist scoped to the agent process.
The Model Context Protocol lets an agent call tools exposed by separate MCP servers. Those servers are usually their own processes, often their own containers, sometimes on their own hosts. When an MCP server does its job, it makes its own outbound connections: to the API it wraps, to the database it queries, to whatever it fetches.
If you configured egress control around the agent's process or container and not around the tool servers it calls, you have built a fence with a gate in it. The agent's own traffic is controlled. The traffic it causes is not. And an injected agent that can choose which tool to call, with which arguments, is choosing what that unconstrained process sends.
The mitigation is straightforward and easy to forget: route the MCP servers' egress through the same proxy, under the same default-deny policy. Each tool server gets its own allowlist, which should be much narrower than the agent's, because a tool server that wraps one API should only ever reach that API.
What to log
Log enough to answer "what did this agent do" without building an archive you regret.
Record for every request: timestamp, which agent or tool server, destination, decision, and which rule matched. Add a body fingerprint, such as a hash and a size, rather than the body itself.
Do not log full request bodies by default. For agent traffic those bodies contain prompts, retrieved documents, and customer data, so a complete log is a copy of everything sensitive the agent has ever touched, sitting in a system with weaker access controls than the source. Capture full bodies only on a block decision, or when an investigation calls for it and someone has turned it on deliberately.
What to do next
- The architecture behind this, including why proxies see what they see, is in Proxies Explained.
- Egress control bounds where an agent can go. Identity for AI agents covers who it is when it gets there, and the two are complementary rather than alternatives.
- If you run MCP servers, Secure your MCP server covers the server side of the hole described above.
- Static credentials sitting in an agent's environment are the thing an injection is usually reaching for. Replace static API keys covers removing them.
- For tooling, see the non-human identity security tools comparison.
Key takeaways
- Controls inside the agent framework are requests, not boundaries. A system that can execute code can open a socket, so the enforcement point has to sit outside it at the network level.
- Start from deny-all and add back from observed traffic. A guessed allowlist manages to be both too permissive and missing what breaks in production.
- Package and artifact registries usually belong in the build, not at agent runtime. An agent installing packages while it works is a supply-chain decision made by accident.
- Every service on your allowlist that accepts free-form text is a potential exfiltration channel, and destination-based policy cannot see it happen.
- Keep the allowlist in version control beside the agent code, so adding a destination is a reviewed change rather than a console click nobody remembers.
- Do not log full request bodies by default. For agent traffic that is a copy of every prompt, document, and customer record the agent has touched.
Frequently asked questions
- Does an allowlist stop data exfiltration?
- No, not on its own. An attacker with prompt injection does not need an attacker-controlled server: they can put the data in a free-text field of a destination you already allow, such as your own issue tracker, chat workspace, or CRM. The request is permitted by policy and the data still leaves. Request-body inspection is what closes that gap.
- What is egress control for an AI agent?
- It means the agent can reach no network destination until you explicitly allow it, and the decision is enforced at a proxy the agent cannot bypass. It matters more for agents than for ordinary software because an agent chooses its own actions at runtime, so you cannot enumerate its destinations in advance.
- Why does MCP traffic escape my network allowlist?
- Because MCP tool servers are usually separate processes or containers that make their own outbound connections when they do their job. If you scoped egress policy to the agent's process, the agent's traffic is controlled but the traffic it causes is not. Route each tool server's egress through the same proxy, with its own narrower allowlist.
- Can I enforce this inside my agent framework instead?
- Not as your boundary. Framework hooks, tool allowlists, and system-prompt instructions are all requests made to a system that writes and runs its own code: if it can execute a shell command it can open a socket. Keep those controls for better error messages and earlier failure, but enforce the real limit at the network.
- Should I log full request bodies from my agents?
- Not by default. Agent request bodies contain prompts, retrieved documents, and customer data, so a complete log becomes a copy of everything sensitive the agent has touched, usually in a system with weaker access controls than the source. Log destination, decision, rule matched, and a body hash and size instead, and capture full bodies only on a block or a deliberate investigation.
Related
Vendor comparisons
Sibling guides