curl, or an SDK
that makes its own HTTP calls, can reach any host without the tool-argument
policy noticing.
The egress proxy adds a second check. It routes the process’s outbound HTTP(S)
through an in-process forward proxy and asks the same PolicyEnforcer about each
request, keyed on the destination host. Egress becomes another gated tool,
net.http_request, sharing the decision type and
the audit trail with everything else.
This is separate from the workspace sandbox, which enforces
network rules in the kernel for the bash tool only. The egress proxy is
framework-agnostic and covers any HTTP client running in the agent’s process.
Turn it on
egress_guard starts the proxy and points the process’s HTTP clients at it (via
HTTP_PROXY / HTTPS_PROXY, which most clients read by default). The agent’s
request code does not change.
api.github.com connect. Anything else is refused before a byte
leaves the process, and the deny lands in the audit stream next to the tool-call
decisions.
Write the policy
In code,net_allow renders the host allowlist into constraints:
net.http_request tool:
subdomains=["example.com"] to match the apex and any *.example.com. A
host restriction is required: net_allow() with only a scheme or port filter
raises, since a rule with no host clause would allow every host. Use
any_host=True when you do want that.
What the proxy sees
For HTTPS, the client opens the connection with a plaintextCONNECT api.github.com:443 line before TLS starts. The proxy decides on the
host there, then relays the encrypted bytes without touching them. It never
holds the keys, so on HTTPS a request exposes only its host, port, and scheme.
Almost all API traffic is HTTPS, so plan around host-level control. Reading the
path or body of an HTTPS request needs TLS interception, which the SDK does not
do (see Limits).
Layering
Egress control sits alongside the other enforcement points. Deploy whichever combination fits the threat model.Limits
- Bypassable unless the runtime forces it. The proxy relies on
HTTP_PROXY/HTTPS_PROXY. Code that setstrust_env=False, or a tool that unsets those vars, skips it. Treat it as intent-shaping in a plain SDK deployment. A sandbox that forces all egress through the proxy is the hard boundary. - Host-level on HTTPS. Path, query, and body are encrypted. Constraining those needs TLS interception, which belongs to a controlled runtime rather than a library.
- One guard per process.
egress_guardsets process-global proxy env vars, so a nested or concurrent guard raises instead of clobbering the first.