Back to blog
2026-06-10Guide

How to Lock Down an AI Agent's Network Egress

By default an agent can call anywhere on the internet — which is exactly how a prompt-injected agent exfiltrates data or phones home. Here's how to put it on an allowlist and record every attempt.

An AI agent's most dangerous capability isn't running code — it's the network. Code that runs in isolation is contained. But the moment the agent can open an outbound connection, a prompt injection or a compromised dependency can POST your data to an attacker's server, pull down a second-stage payload, or quietly beacon out.

By default, a sandbox lets the agent reach anything. That's the right default for getting started, but it's the wrong one for production. Egress control is opt-in, and this guide is how you opt in — plus how to record every connection the agent tries to make.

The model: allow what you need, deny the rest

Declaw enforces egress at two layers, transparently:

  • Kernel (Layer 3/4): raw IP and CIDR rules applied directly as iptables rules — zero userspace overhead.
  • Proxy (Layer 7): domain rules matched against the TLS SNI or HTTP Host header, enforced by a per-sandbox proxy the workload can't bypass.

You express both through one NetworkPolicy. The pattern for a locked-down agent is: deny everything, then allow the short list of hosts it legitimately needs.

Step by step

1. Install the SDK

pip install declaw

(Same policy object exists in the TypeScript, Go, and CLI clients.)

2. Deny all egress, then allow only what the agent needs

from declaw import Sandbox, SecurityPolicy, NetworkPolicy, ALL_TRAFFIC

sbx = Sandbox.create(
    template="base",
    security=SecurityPolicy(
        network=NetworkPolicy(
            allow_out=["*.openai.com", "pypi.org"],
            deny_out=[ALL_TRAFFIC],          # ALL_TRAFFIC == "0.0.0.0/0"
        ),
    ),
)

Allow rules always win over deny rules, so deny_out=[ALL_TRAFFIC] is a safe baseline — list everything to block, then carve out the exact hosts you trust. For a total blackout (no egress at all), the shorthand is Sandbox.create(allow_internet_access=False).

3. Match hosts the way that fits

Domain entries support three forms:

NetworkPolicy(allow_out=["api.openai.com"])    # exact host
NetworkPolicy(allow_out=["*.openai.com"])      # any subdomain (not the bare apex)
NetworkPolicy(allow_out=["~.*\\.anthropic\\.com"])  # ~ prefix = regex

IP and CIDR entries skip the proxy entirely and become kernel iptables rules:

NetworkPolicy(allow_out=["1.1.1.1", "10.0.0.0/8"], deny_out=[ALL_TRAFFIC])

4. Know what's handled for you

  • The cloud metadata endpoint (169.254.169.254) is always blocked — in every sandbox, regardless of policy. This is the classic SSRF path to steal cloud credentials, and it's a hardcoded DROP you can't accidentally allow.
  • DNS is auto-allowed. When any domain rule is present, outbound DNS to 8.8.8.8 is permitted automatically so name resolution still works — you don't add it yourself.

5. Record every egress decision

Audit logging is on by default — no configuration. For each connection the proxy records an egress_allowed or egress_blocked event with the destination domain, IP/port, and the rule that fired. That egress_blocked stream is your exfiltration tripwire.

from declaw import Sandbox, SecurityPolicy, AuditConfig

# Audit is already on. To OPT OUT for a sensitive workload:
sbx = Sandbox.create(
    template="base",
    security=SecurityPolicy(audit=AuditConfig(enabled=False)),
)

What to check

Check Why it matters How
Egress is open by default An unrestricted agent can reach any host Set deny_out=[ALL_TRAFFIC] and an allow_out list
Allow only what's needed Least privilege shrinks the exfil surface Keep allow_out to the real dependencies
Metadata service is dead Blocks SSRF → cloud-credential theft curl 169.254.169.254 fails in every sandbox
DNS still resolves Domain filtering needs working DNS 8.8.8.8 is auto-allowed when domain rules exist
Blocked attempts are recorded Detect an agent trying to phone home egress_blocked events (audit on by default)

Limitations to know

  • The default is full egress. Filtering is something you turn on — an out-of-the-box sandbox reaches the whole internet. Treat the allowlist as a required production step, not a default.
  • Domain filtering inspects outbound TCP. Under the deny-all baseline in this guide, the kernel's fail-closed FORWARD DROP policy also drops non-DNS UDP such as QUIC/HTTP3 — so clients transparently fall back to TCP, where the domain rules apply. DNS is the one UDP path that's special-cased and allowed.
  • Audit retrieval is platform-side today. Events are recorded and kept for 7 days, but there's no self-serve SDK call to pull them yet — access them via the console or your Declaw administrator. Request/response bodies are never logged.

Next step

Lock one sandbox to a single domain, then run curl to a blocked host inside it and watch the connection get refused — that's the whole control in one command. Grab the SDK at declaw.ai.

Network egress is half the exfiltration story; the other half is the credentials the agent carries. See How to Give an AI Agent Code Execution Without Handing Over Your Credentials for keeping secrets out of the sandbox entirely, and Why Sandboxes Alone Won't Secure Your AI Agents for the bigger picture.