Egress Control
Egress control limits what is allowed to leave a system: which destinations it may contact and which kinds of data may be sent there. Ingress controls ask what may come in. Egress controls assume that something inside may be compromised, confused, or manipulated, and bound the damage it can do on the way out.
Why it matters for LLM applications
A model that reads untrusted text can be steered by it. For data exfiltration, the harmful combination is private data in the context, untrusted content that can issue instructions, and a channel to an outside destination. Egress control removes the third leg of that combination. It does not prevent other harms, such as an unauthorized internal change or a false answer. A tool such as send_email(to, body) with a free to field gives an attacker a channel; the model only needs to be persuaded once. Rendered replies are also a channel, as a link or image URL that the user's browser fetches (see Data Exfiltration via Markdown Images).
Mechanisms
- Remove the free destination. The best control is not letting the model choose. A
send_status_email(order_id)tool that reads the recipient from the order record has no recipient argument for an attacker to fill. - Allow-lists. Permit only named destinations, and deny everything else by default. This holds for outbound HTTP calls from tools, URLs in rendered replies, and domains reachable from a sandbox. A deny-list of known bad hosts fails because attacker hosts are unlimited.
- Data-class rules. Compare what is in the context with who is allowed to receive it. One workable rule: an outbound call is allowed only if its recipient is in the intersection of the audiences of everything in the context. If the context holds an order readable by one customer and staff, mail may go to them, not to an outside address.
- Network-level limits. A proxy or firewall that allows only listed hosts catches calls that bypass the application's own checks.
- Hold for review. A blocked request can be queued for a person instead of failing.
Allow-list matching must parse, not prefix-match
Naive string tests are defeated by constructed URLs. A hypothetical allow-list containing only shop.example.test over HTTPS, applied by parsing the URL and comparing the exact hostname, gave:
| URL | Parsed check | Prefix test startswith("https://shop.example.test") |
|---|---|---|
https://shop.example.test/track/ord_8 | allowed | allowed |
https://shop.example.test.evil.example.test/x | blocked | allowed |
https://shop.example.test@evil.example.test/x | blocked | allowed |
http://shop.example.test/x | blocked | blocked |
https://evil.example.test/?r=https://shop.example.test/ | blocked | blocked |
https://shop.example.test:8443/a | blocked | allowed |
In the second row the allowed name is only a prefix of another domain; in the third, shop.example.test is the username part and the real host is after the @. A correct check parses the URL, requires the scheme and port, rejects embedded credentials, normalizes case, and compares the whole hostname to the list. Redirects need the same treatment, since an allowed host can forward to a disallowed one.
Limits
An allow-listed destination can still carry data in its path or query. Egress control bounds where data may go; it does not inspect every byte, so combine it with minimizing what enters the context. It also depends on being at a choke point: if a second outbound path exists, such as a tool that fetches arbitrary URLs, the control on the first is bypassed. And it can block legitimate use, which is why the allow-list needs an owner and a process to add entries.
Discover more from Insightful Data Lab
Subscribe to get the latest posts sent to your email.
