Network Egress Controls for Agent Sandboxes
Blocking outbound traffic is the only control that stops agent data theft.

Network egress control is what separates an agent sandbox that's ready for production from one that's a demo waiting to leak data. Egress is outbound traffic leaving through some specific, identifiable channel: the path from a compromised prompt to the external endpoint that receives whatever got stolen. Close that path first. Nothing else about the sandbox matters much until it's closed.
The threat here doesn't resemble anything traditional application security trained teams to expect. Ordinary code has a fixed instruction set, written and reviewed before it ever runs, and a security team can read it end to end and know exactly what it does. Agent code gets generated at runtime, from inputs an attacker may already control, so the instruction set doesn't exist until the moment of execution. Palo Alto Networks' Unit 42 showed this gap directly: ChatGPT-4o, deployed as an autonomous agent, carried out SQL injection, server-side request forgery, and unauthorized data exfiltration in scenarios where the same model, used as a plain chat interface, refused every time. Same weights, different execution context, a completely different risk profile.
The attack chain is short, and by now it's well documented. Adversarial content reaches the model. The model treats that content as an instruction instead of data to reason about. Generated code fires off an outbound call, and data leaves the perimeter. Four steps, no exotic tooling required. Prompt injection still has no deterministic fix, only probabilistic, layered mitigations that lower the odds without ever closing them to zero, which is exactly why the sandbox's job is containment: nobody can promise an injection won't land, so the design has to assume it will and ask what happens the moment after. Experiments on computer-use agents found end-to-end exfiltration success rates as high as 85%. Open egress turns a successful injection into a completed theft almost automatically.
Four threat categories fall out of this, and egress control has to answer for all of them: prompt injection, where instructions get smuggled into retrieved content; tool misuse, where an agent calls an approved tool with parameters well past what the task intended; credential exfiltration, where an agent reads secrets sitting in its own environment and ships them out; and unintended side effects, where individually reasonable actions add up to something harmful. Egress control won't stop the injection from landing. What it does is stop the data from leaving, and that's precisely why it functions as the single most important control at the boundary of a production deployment.
What makes agent sandboxes a different execution surface from ordinary containers
A standard containerized app has a known network surface, fixed by whoever built and deployed it. An agent's network surface gets decided at runtime, by code the agent writes itself in response to inputs that might already be compromised. That's the core asymmetry, and it means the sandbox around an agent has to do more work than the sandbox around a conventional service.
Docker containers share a kernel with the host, and that shared kernel is the whole problem. With standard containers, the workload sits one system call away from host compromise. This isn't theoretical. CVE-2024-21626, a runc vulnerability, exploited the container runtime itself to let a container escape onto the host. Layer on a 2025 Veracode report finding that 45% of AI-generated code fails security tests, and the picture turns uncomfortable fast, because that failing code is exactly what an agent sandbox spends its day running.
Langflow's CVE-2025-3248 makes the danger concrete instead of abstract. An unauthenticated API endpoint accepted a raw Python string and passed it to exec() (by way of compile()), no authentication, no sandboxing in front of it, exploitable through something as ordinary as a Python decorator or a default argument. One HTTP request could produce a reverse shell or pull files off the system. CISA added the vulnerability to its Known Exploited Vulnerabilities catalogue on May 5, 2025. The lesson outlasts this one product: any agent infrastructure that treats generated code as trusted has already lost its perimeter, whether or not anyone's found the exploit yet.
By 2026, production practice has settled into a rough hierarchy, and hardened containers lose that argument. MicroVMs, the Firecracker and Kata Containers approach, give each workload a dedicated kernel and hardware-level isolation, and represent a meaningfully stronger isolation guarantee than shared-kernel containers for running agents in production. gVisor, a user-space kernel that intercepts system calls without booting a full virtual machine, is a real step up from a bare container, but it isn't the same guarantee as a dedicated kernel. Hardened containers belong in development environments. They are not sufficient for production agent execution against untrusted, generated code, and treating them as though they were is how teams end up explaining a breach after the fact.
None of this is separable from the egress question. A workload that escapes its isolation boundary carries its network permissions out with it, so egress policy enforced only at the application layer gets sidestepped entirely the moment agent-generated code breaks out to the host. Isolation decides what the agent can execute. Egress decides where that execution is allowed to reach. Both need hardening, at the correct layer, or whichever one's left soft becomes the way in.
Why default-deny is the only coherent starting posture
Two starting postures exist, and default-allow loses this argument before it even begins. Default-allow means every domain is reachable until somebody notices a problem and blocks it, so the list of blocked destinations grows after the fact and, by definition, never finishes growing. Default-deny means nothing is reachable until somebody explicitly approves it, so the list of approved destinations is fully known and bounded at every moment.
That asymmetry matters more for agents than for nearly anything else in a modern stack, because an agent's outbound calls aren't known at deploy time. They're generated from prompts that may already have been tampered with by the time the agent acts on them. A team can't retroactively block what it never had the ability to list in advance. Harmonic Security's AI Security Handbook (last reviewed August 18, 2026) puts it directly: network egress is the path from a compromised prompt to external data loss, and default-deny is the only clean starting point for an agent runtime.
Managed cloud sandboxes that ship with network access disabled until the environment configuration explicitly turns it on are built around this logic. Every reachable domain is the result of a deliberate decision, so the default works for the operator instead of against them.
The AWS Instance Metadata Service shows exactly why fixing things after the fact loses to deny-by-default. Any agent that can reach 169.254.169.254 can pull host instance credentials straight out of that endpoint. It isn't "the internet," so it never shows up on a blocklist built with external destinations in mind, and a team focused on stopping traffic to suspicious domains has no natural reason to think about an internal-looking IP at all. Default-deny catches this automatically, since nothing is reachable unless someone added it. Default-allow requires someone to have already known to add IMDS to a blocklist, which is exactly the foresight that got skipped in the incidents that made this endpoint infamous in the first place.
The attack path runs clean: a prompt injection buried in a retrieved document tells the agent to call the IMDS endpoint, or an attacker-controlled one instead. The fix is default-deny at the network layer, paired with an explicit allowlist of approved domains and either a block or IMDSv2 enforcement on the cloud metadata endpoint specifically. None of this means an agent can't reach anything useful. It means every destination it does reach is the result of a decision someone made on purpose, one that can be reviewed, versioned, and audited later.
Building the allowlist: scoping egress to what each task actually requires
Scope the allowlist to the task, not the system. A task that needs one specific API should get exactly that API, not the full set of endpoints every task across the whole system has ever needed at some point in its history. Disposable sandboxes make this discipline easy to hold onto, since the allowlist dies with the container: the blast radius of a breach is bounded by the session and carries nothing forward into the next one.
Five categories of destination deserve their own allowlists and their own owners, not one undifferentiated pile. Model API access, through the LLM provider's own endpoint. Package registries, whether that's npm, PyPI, or an internal mirror. Approved vendor APIs, things like GitHub, internal webhooks, or a specific data provider the task actually calls. Internal services, gated by explicit path-level permissions rather than blanket internal network access. General web browsing, which, if a task needs it at all, sits under the exact same allowlist logic as everything else. Nothing gets a pass because it sounds routine, and "sounds routine" is precisely the excuse that lets a category slide through review unexamined.
Build allowlists on domain names, not IP addresses. IPs rotate, and shared content delivery networks serve thousands of unrelated hosts off a single address, so an IP-based rule that permits one CDN IP quietly permits every site sitting behind that CDN. The correct enforcement point for HTTPS traffic is the SNI field exposed during the TLS handshake, which lets a proxy filter by domain even while the payload itself stays encrypted.
TLS 1.3's Encrypted Client Hello hides the hostname from that handshake, blinding SNI-based filtering for anyone using it. Agents with a stable, well-known set of destinations barely notice, since their allowlists never depended on inspecting every hostname on the fly. Research agents that fetch arbitrary URLs at runtime are a different animal, and they need a different enforcement approach.
DNS is the gap that gets missed the most. A filter working at the application-traffic layer does nothing to restrict DNS resolution on its own, so an agent that can resolve arbitrary domain names can map internal network topology, probe for internal hostnames, or use DNS lookups as a covert channel, even while its outbound traffic at that layer stays fully blocked. DNS can carry data out entirely on its own, encoded directly into the lookup names and exfiltrated through the resolution process, no HTTP request needed at all. The fix is pointing agent DNS traffic at an internal resolver that itself respects the allowlist, or restricting resolution to approved domains outright, instead of treating DNS as somehow outside the policy's reach.
Web search and browser tools deserve the same scrutiny as a raw shell, not less, because a friendly name doesn't change what a tool actually does. Injected content can carry data out through a query string or a crafted URL just as easily as through a curl call, so these tools belong under the same allowlist discipline as any other egress path. Never exempt them because "search" or "browse" sounds harmless. That reasoning is exactly what gets exploited. Every entry on the list should record why the task needs that domain, not just the hostname, because that question, asked at review time, is what keeps the list from turning into an unauditable pile of stale exceptions nobody remembers approving.
The enforcement layer: why application-level filtering is not enough
Filtering that lives only in application code can be routed around, because agent-generated code runs in the same process space as the logic meant to police it. If the check and the thing being checked share an execution context, a compromised agent just goes around the check. Enforcement has to sit somewhere the agent's own code can't reach or modify. That's not a nice-to-have, it's the whole design constraint.
That means pushing controls down to the network layer: eBPF programs or policy enforced at the container-networking layer, filtering egress independent of whatever the agent's code decides to do; resource limits enforced at the cgroup level rather than inside application logic, since generated code bypasses application-level limits the same way it bypasses application-level filtering; and the cloud metadata endpoint blocked via iptables as a defense-in-depth measure, following AWS's own IMDS guidance, even though that rule alone isn't the primary control.
Proxy-mediated egress is the production pattern that pulls this together. Outbound calls route through a layer that inspects, filters, and injects credentials before a request ever leaves the perimeter, so the sandbox's own code never touches a real credential and has no way to bypass a check it never even sees. Proxy-mediated secrets injection is a concrete example of this pattern: plaintext secrets never enter the sandbox at all. Placeholders in outbound HTTPS headers get swapped for real values by the proxy layer, so a leaked request to the wrong endpoint leaks nothing usable.
Static egress IPs solve a related but separate problem. All outbound traffic exits through a dedicated, publicly routable address via NAT, which lets enterprise firewalls and third-party APIs that enforce IP-based access control allowlist that fixed address on their end. Static IPs establish who's calling. Domain filtering governs where the call is allowed to go. They control opposite ends of the same connection, and a real setup needs both. Neither substitutes for the other.
Data loss prevention operating at the payload layer catches what network-level rules structurally can't: a prompt injection that talks the agent into sending sensitive data to an endpoint that's genuinely on the allowlist, just not the one that task was ever meant to use. The domain checks out, so network filtering waves it through. Only payload inspection has any chance of noticing the content itself doesn't belong there. Lateral movement needs its own explicit gate too. Sandbox-to-internal-service traffic should stay blocked by default unless a policy engine has explicitly permitted that specific path for that specific session, not for the account or the deployment as a whole.
Credentials minted fresh per session and revoked the moment the session ends are what make the rest of this hold together. A compromised session that ends actually ends. It can't reach back out later using credentials that no longer exist.
Common failure modes in egress policies that teams ship to production
The package-install antipattern shows up constantly, and it's the one most teams recognize only after the fact. Network access gets opened wide for the dependency-installation phase, and nobody ever narrows it back down once the agent starts actually executing the task. The broadest window the system will ever have quietly becomes the permanent one.
Tool-level inconsistency is just as common, and just as avoidable. A bash tool reaches domains that the browser tool inside the very same agent is blocked from touching, simply because policy got defined per tool instead of per session. An attacker who can invoke bash has, in effect, already beaten whatever the browser policy was supposed to enforce, because the restriction was never really about the session. It was only ever about one tool within it.
Undocumented allowlists rot quietly. Hostnames get added over time with no record of why any particular one was needed, the list only grows, old entries never get pruned, and eventually nobody on the team can say with confidence whether a given domain is still required for anything at all.
The approved-but-wrong-endpoint problem is how so many real incidents actually play out: a prompt injection drives the agent to send data to a domain that's on the allowlist, just not for that purpose, and the allowlist waves the request through since the domain itself checks out fine.
Logging failures compound all of this after the fact. Logs often capture that a network request happened, but not the prompt that triggered it, not the tool chain involved, not the session context around it, and forensic work after an incident hits a wall almost immediately as a result. Shell network tools like curl and wget, left enabled inside the sandbox, hand agent-generated code a direct egress path that skips proxy-level filtering. They should stay off unless they're part of an explicitly approved and audited workflow, not left on by default because nobody thought to turn them off.
Eventually this stops being an engineering problem and turns into a business one. When agent infrastructure hits the security review stage of an enterprise procurement cycle, an undefined egress posture stalls the deal. Network controls stop being a line item on a feature list and become a contract-blocking requirement. "It isn't restricted" ends the conversation before it goes anywhere else.
How managed platforms handle egress versus self-configured infrastructure
Whether default-deny is the starting state by default marks the real difference between these two approaches, and self-configured infrastructure is where that default most often fails to get built at all. A managed platform makes default-deny the baseline of every fresh sandbox. Self-configured infrastructure requires a team to build it themselves, correctly, before the agent ever runs its first task, and skipping that step is how most of the failure modes above get into production in the first place.
Blaxel treats these controls as platform-level primitives rather than something bolted on by each customer: domain filtering, proxy-based secrets injection, dedicated egress gateways (currently in private preview, offering static outbound IPs), and support for custom domains. The proxy secrets injection model intercepts outbound HTTPS traffic and injects headers, body fields, and secrets server-side, so plaintext secrets never enter the sandbox environment at all. Sandboxes run in microVMs on a custom Firecracker fork, with resume times under 25 milliseconds, which keeps the isolation guarantees intact without the startup cost a full virtual machine boot would normally carry.
The gap between these two approaches comes down to a real tradeoff, not a matter of taste: whether default-deny gets decided once, at the platform level, or every single time, by every team that builds its own agent infrastructure from scratch and hopes it remembered every step along the way. Betting on the second option, for most teams, is a bet against their own future workload.
Sources
- 3.3 Network egress control | AI Security Handbook by Harmonic Security
- Agent Sandbox Egress Control & Outbound Allow-Listing | Blaxel
- softwareseni.com
- Practical Security Guidance for Sandboxing Agentic Workflows and Managing Execution Risk | NVIDIA Technical Blog
- Audit an AI Coding Agent's Network Egress Before It Gets a Shell
- stride.build
- agentpatterns.ai


