Most networks inspect what comes in and let almost anything go out. Egress filtering is the other half of the job: deciding which outbound traffic may leave, and where it may go. It matters again now that AI agents open their own outbound connections from laptops, sandboxes and Pods.

What is egress filtering?

Egress filtering is the practice of checking outbound traffic against a set of rules and blocking, or at least logging, every connection the rules don’t allow. It covers egress traffic leaving a network, a single host or a container, and asks the same question of each connection: may this source reach this destination over this protocol?

The NIST glossary defines it as “Filtering of outgoing network traffic,” citing NIST SP 800-41 Rev. 1, its guide to firewalls and firewall policy. The same control goes by outbound traffic filtering, egress traffic filtering and egress control; egress security is the broader goal. In networking and software, egress simply means leaving.

Every egress rule has four parts:

  • Source: who or what opens the connection: a subnet, host, workload or process.
  • Destination: an IP range, a hostname or a service.
  • Protocol or port: how it connects, for example TCP 443 or UDP 53.
  • Action: allow, deny or log.

Rules can be enforced at a perimeter or cloud firewall, an egress gateway, a host firewall, a forward proxy or a sidecar next to the workload. The closer the enforcement point sits to the workload, the more it knows about what opened the connection.

What is egress traffic? Ingress vs egress filtering

Egress traffic is any traffic leaving a boundary: a corporate network, a cloud VPC, a host or a Kubernetes Pod. Ingress traffic crosses the same boundary inward. When a laptop on the internal network calls an API on the internet, the request is egress for the office and the response is ingress.

An egress IP is the public source address that outbound traffic appears to come from, often a NAT gateway’s address. Partners allowlist it, so teams send outbound traffic through one stable exit.

Ingress filteringEgress filtering
DirectionArriving from external networksLeaving for external networks
What it protectsYour services, from outside attackersYour data and other networks, from a compromised host inside
Typical rulesExpose only published services; drop spoofed internal source addressesAllow only the destinations each workload needs; send only your own source addresses
Example threatAn exploit sent to an exposed portMalware uploading stolen files or calling its operator

Anti-spoofing applies both ways. Inbound, drop packets from outside that claim an internal source address. Outbound, let packets carry only addresses you own, so a compromised host can’t forge another network’s.

Ingress filtering checks each incoming connection against what may enter, on every boundary facing external networks. Egress filtering belongs wherever a compromised system inside could cause harm by sending traffic out, which is almost everywhere.

Why does egress filtering matter?

Ingress controls fail eventually: a phishing click, a vulnerable dependency, a leaked credential. Once something malicious runs inside, it needs outbound connections to be useful, and egress security limits each kind:

  • Data exfiltration. Stolen data has to leave over some protocol; every path you close is one less channel.
  • Command-and-control callbacks. Malware checks in with its operator; blocking unknown destinations cuts that link.
  • Spread. A worm scans for other hosts to infect, inside your network and beyond.
  • Attacks on others. Compromised devices get drafted into DDoS attacks.
  • Unauthorized services. A user’s own mail server or tunnel skips the official controls.

The Software Engineering Institute at Carnegie Mellon (SEI) ties this to real incidents in a 2018 article. WannaCry spread in 2017 through SMB on port 445, so filtering it in both directions would have slowed it. In the 2016 attack on the DNS provider Dyn, infected devices sent floods of DNS traffic over port 53.

Egress filtering doesn’t prevent the first compromise. It limits what the compromised host can do next, and the deny logs it leaves are often the first sign that something inside is misbehaving.

Default deny vs default permit egress

Default permit allows all outbound traffic and blocks a list of known-bad destinations. Default deny blocks all outbound traffic and allows a list of known flows.

The SEI article states the trade-off plainly. Default deny is the safer stance, but only if you know every flow that has to leave; default permit is simpler to implement and lets unknown traffic out. Starting a new network on default deny is far easier than retrofitting an existing one, where it breaks applications nobody listed.

PostureWhat leavesRollout effortHow it fails
Default permitEverything except what you blockLow: add blocks as threats appearOpen: a new exfiltration channel works until someone blocks it
Default denyOnly the flows you allowHigh: every needed flow has to be known firstClosed: a missing rule breaks an application until someone allows it

To reach default deny without an outage, go one workload at a time:

  1. Observe its outbound flows in log-only mode, long enough to catch monthly jobs.
  2. Scope the first rollout to a workload with few destinations, such as a build server.
  3. Enforce default deny on that workload only.
  4. Review denied flows: each is a missing rule or an attempt worth investigating.
  5. Widen to the next workload.

Egress filtering best practices

These egress filtering best practices hold whatever enforces them. Items 2 to 5 follow the SEI’s recommendations, written for large organizations.

  1. Inventory what needs to leave: package registries, update servers, SaaS APIs, partners.
  2. Deploy anti-spoofing filters. Only packets sourced from your own registered, routable addresses should leave. Private RFC 1918 addresses, such as anything in 10.0.0.0/8, should never reach the internet.
  3. Keep internal-only services inside. Windows file sharing and RPC (SMB on TCP 445, NetBIOS on TCP/UDP 137-139, MS RPC on TCP/UDP 135) and management protocols (SNMP on UDP 161-162, Syslog on UDP 514, TFTP on UDP 69) rarely need the internet. If a partner needs one, allow it to that partner’s addresses only.
  4. Block services used mostly for abuse, such as IRC (typically TCP 6660-6669), a common command-and-control channel.
  5. Pin DNS, SMTP and web traffic to known hosts. Only internal resolvers send DNS (53), only mail relays send email over SMTP (25), and if you run an outbound web proxy, nothing else uses ports 80 and 443.
  6. Log denied flows and read them. An unread deny log hides both broken rules and real attempts.
  7. Scope rules to workload identity rather than IP ranges where you can: a service account, a Pod label, a process.
  8. Roll out new rules in log-only or dry-run mode, then enforce.

Layer 3/4 vs layer 7 egress filtering

Layer 3/4 egress rules match the network and transport headers: IP addresses, ports and protocol. Every firewall supports them. Their blind spot is shared infrastructure: when many services sit behind one CDN or load balancer address, allowing the address allows all of them.

Layer 7 egress filtering reads the application protocol: the hostname (from the TLS SNI field or the HTTP Host header), the HTTP method and path, a database statement or an API action. It can refuse one action on a destination you otherwise permit.

What an IP allowlist misses: the Claude Code devcontainer

When we took apart the Claude Code devcontainer firewall, it was a clear case of this gap. Anthropic’s reference devcontainer has an init script that looks up each allowlisted hostname with dig and permits the returned IP addresses in iptables. Nothing checks the hostname on the connection itself.

That leaves three ways out. A load balancer on an allowlisted IP that routes by SNI or Host header serves other hostnames too. Port 22 is open to any IP address. And allowlisted services accept uploads: a secret can leave inside a published npm package or a GitHub gist.

Reading past the hostname in HTTPS means decrypting the traffic, which is what SSL/TLS inspection does. Command allowlisting is a separate control: it limits the shell commands an agent may run, not the traffic those commands produce.

Egress firewall vs egress proxy vs egress gateway

Many products combine the three. What separates them is where each sits and how much of the connection it sees.

  • Egress firewall: matches packets or connections against addresses and ports, at a network boundary or on the host.
  • Egress proxy: a forward proxy for outbound connections. The client’s connection ends at the proxy, so it sees the hostname and, with TLS inspection, the request.
  • Egress gateway: the single exit for a network, VPC or service mesh, with a stable egress IP and one place for policy.
Where it runsWhat it seesIdentity it knowsHow it gets bypassed
Egress firewallNetwork edge, security group or hostIP addresses, ports, protocolSource address or hostAn allowed IP serving other hosts; tunnels inside allowed traffic
Egress proxyOn a host, in a sidecar or at the edgeHostname; requests with TLS inspectionThe user or workload, if it authenticates themIn explicit mode, clients that ignore proxy settings
Egress gatewayAt the exit of a network, VPC or meshWhatever runs there: firewall rules, a proxy or bothSource network, or the mesh’s workload identityAny route out that skips the gateway

Teams often stack them: a gateway as the only route out, hostname and request rules enforced there, and a firewall that drops anything leaving another way.

Why is egress control hard to get right?

Egress control is simple to describe and tedious to operate:

  • Allowlists age. SaaS providers, package registries and CDNs change IP addresses without notice, so rules written against hostnames last longer than rules written against IPs.
  • Default deny breaks things. On an existing network, the flows nobody inventoried (OS updates, telemetry, license checks) fail first.
  • Encryption hides the request. Layer 7 rules on HTTPS need TLS inspection, and clients that pin certificates or ship their own trust store fail unless you exclude them.
  • DNS is a channel too. Send DNS only to internal resolvers, and watch for DNS over HTTPS to public resolvers, which looks like ordinary web traffic.
  • Proxies can be skipped. An explicit proxy only sees clients configured to use it; anything else goes straight out. Block direct egress at the network layer, or intercept transparently.

The pattern that works: scope the rule to one workload, observe its traffic, then enforce. Egress control fails when a team tries to cover the whole network in one change.

How do you filter egress traffic from AI agents and sandboxes?

An AI coding agent on a laptop runs as the engineer who started it: same OS user, same device, same IP address, so a network firewall can’t tell its connections apart. It also starts child processes (git, curl, a headless browser), and cloud agents run in short-lived VMs and Pods.

A domain allowlist helps less than it seems. github.com serves clones and pushes on the same hostname, so giving an agent read access to code also lets it push code. Package registries and paste sites work the same way. Kevin Qiu, Lead Security Engineer at Latent Health, describes the moment teams notice this:

“Going from 0.0.0.0/0 to an allowlist felt like progress, until we realized every allowed domain is still an exfiltration channel. Formal lets our production agent do the work safely.”

— Kevin Qiu, Lead Security Engineer @ Latent Health

Filtering agent egress well takes five things a perimeter firewall doesn’t have:

  • Process identity, including ancestors, so a curl the agent spawned counts as the agent.
  • Protocol classification, to tell LLM, MCP, git, SSH and cloud API calls apart on one port.
  • Per-request decisions, so a read passes while a write to the same host is refused.
  • The human behind the agent, carried by a short-lived token such as OIDC, not a shared secret.
  • Logs tying each request to the agent and its human.

Our egress proxy for AI agents page covers why allowlists fall short for agents. The same controls apply to AI tools employees install on their own (shadow AI).

What about egress traffic from Kubernetes Pods?

Kubernetes NetworkPolicy is the built-in control for egress traffic from Pods. The Kubernetes documentation places it at the IP address or port level (OSI layer 3 or 4): which Pods, namespaces and IP blocks a Pod may reach, on which ports. Hostname and request rules need an egress proxy in the Pod’s path, such as a Kubernetes egress sidecar.

How does Formal filter agent egress?

We built Formal Endpoint to sit on the path of agent traffic on macOS and Linux machines, Kubernetes Pods, Amazon ECS tasks and cloud agent VMs.

Network rules pick which connections the Endpoint takes over. Each rule is a CEL condition with up to three stages: pre_tcp, which only macOS evaluates, then pre_tls and post_tls. A rule can test the process and its ancestors, hostname, port, user and groups, and, after TLS terminates, the classified protocol: LLM, MCP, HTTP, SSH, cloud APIs or databases.

Interception is opt-in. Traffic that matches no rule passes through uninspected, so default deny applies inside the traffic a rule covers, not to the whole machine.

In the Codex Desktop guide, a rule selects Codex and its process tree, and a Rego policy allows model traffic and MCP servers registered by name while refusing direct web search and the browsers Codex opens. A second guide stops agents and their children from pushing code over SSH or HTTPS. Both guides are macOS-only, and policies can start in Draft or Dry-run.

The limits: network rules and Transparent Mode aren’t on Windows yet. On Fargate, the Endpoint is an HTTP/HTTPS proxy, which a client ignoring proxy settings goes around. Linux matches agents by process name; code signatures are macOS-only. More in secure web gateway for AI agents.