Agent Network Access Control: Egress Is the Real Risk
An agent with a shell and open network egress can exfiltrate anything it can read. How to scope outbound access without breaking the toolchain.
Most agent security work goes into what the model is allowed to run. Far less goes into what it is allowed to reach. That is backwards: a destructive command damages one sandbox, while an unrestricted outbound connection turns every secret the agent can read into a secret someone else has.
Egress is also the leg that makes prompt injection worth attempting. An injected instruction that cannot reach the network is an annoyance. The same instruction with a working outbound path is a data breach.
Default deny, then open what the task needs
The workable posture is no outbound access unless a rule permits it. This sounds strict until you write down what an agent genuinely needs, which is usually a short list: your model provider, your package registry, your git remote, and occasionally a documentation host.
Enumerating that list has a useful side effect. It forces an explicit answer to what the agent is meant to talk to, which is a question most teams have never asked directly.
Start from deny in a scratch environment and run a few representative tasks. The failures tell you the real dependency list far more accurately than guessing, and the list is usually shorter than expected.
Where to enforce it
The enforcement point matters more than the policy language. Controls the agent can bypass are documentation, not controls.
An HTTP proxy that the tools are configured to use is the easiest thing to deploy and the easiest thing to circumvent, because anything opening a raw socket ignores it. It is fine as a convenience layer and poor as a boundary.
Network policy at the container or VM level — an egress firewall on the sandbox, or a network namespace with explicit routes — holds regardless of what runs inside. This is the same argument as for filesystem isolation, and the same conclusion applies: put the boundary where the code cannot argue with it. Agent sandboxing covers the isolation primitives.
DNS-based allowlisting is convenient but partial. It filters by hostname while the connection is made by address, so it stops casual access and not a determined path. Combine it with address-level rules rather than relying on it alone.
The credential question comes first
Network rules limit where data can go. They do not limit what data exists to send, and the second problem is usually easier to fix.
Audit what is present in the agent environment. Cloud credentials inherited from the host, a shell profile that exports tokens, a checked-in .env, an SSH agent socket forwarded into the container — these arrive by accident far more often than by decision.
An agent that needs to push to a remote needs a credential scoped to that remote, not the developer keychain. An agent that needs a package registry needs a read token. Scoping credentials narrowly means an egress failure is a contained incident rather than a serious one.
Fetching the web is the sharp edge
Web access is the case where the rules get genuinely hard, because the point of the tool is to retrieve content you have not vetted.
Treat everything fetched as untrusted input, in the same category as user-supplied data. Text in a page or an issue thread has no authority over the agent, and the system prompt should say so explicitly. Prompt injection and agent security covers the failure patterns.
Structural defences do more than instructions here. Wrap fetched content in a clearly delimited block labelled as retrieved data. Strip scripts and hidden elements before the text reaches the model. Keep the fetch tool separate from any tool that can write or send, so a single injected instruction has no direct path to an action.
Blocking access to internal address ranges from the fetch tool is worth doing on its own. A fetch tool that will resolve a private address gives anything that can influence a URL a way to reach services that assumed they were unreachable.
MCP servers are network access with extra steps
A tool server is a general-purpose outbound channel wearing a tool schema. Adding one is a network access decision even when it never appears in your firewall rules, because the server can reach whatever it likes on its own side.
Apply the same scrutiny you would to a dependency: who runs it, what credentials it holds, what it can reach. A server you did not write, running with your tokens, is the widest possible grant. What is MCP covers the protocol; the trust question is separate from it and more important.
Log the connections
Record outbound attempts with destination, tool, whether they were allowed, and the turn number. Denied attempts are the interesting half.
Legitimate denials tell you the allowlist is too tight and which rule to add. Unexpected denials — a destination nobody configured, appearing in the middle of a task involving fetched content — are the clearest injection signal you will get, and they are invisible without the log. Agent audit logging covers keeping these records usable.
A practical starting configuration
Deny egress by default at the sandbox boundary. Allow the model provider, the package registry and the git remote by address. Give the agent scoped credentials only for those, and nothing inherited from the host.
If web fetching is needed, run it as a separate isolated component that returns text into the transcript and holds no credentials at all. Then log every attempt and review the denials weekly.
This costs an afternoon and removes the entire category of failure where an agent quietly sends something somewhere. It also pairs naturally with restricting what the agent can execute in the first place. Agent shell access safety covers that side.
Common questions
Why is outbound network access more dangerous than shell access?
A destructive command damages one sandbox you can rebuild. An open outbound path turns every credential and source file the agent can read into data someone else can hold, and it is what makes prompt injection worth attempting at all.
Is an HTTP proxy enough to control agent egress?
Only as a convenience. Anything that opens a raw socket ignores proxy configuration. Enforce at the container or VM network layer so the rule holds regardless of what runs inside the sandbox.
How should a web fetch tool be treated?
As untrusted input. Wrap retrieved content in a delimited block labelled as data, strip scripts and hidden elements, block private address ranges, and keep the fetch tool separate from any tool that can write or send.