AI Agent Egress Controls: Stop Autonomous Tools From Calling the Wrong Systems
AI agents need hard outbound boundaries. Build destination allowlists, scoped credentials, payload checks, and approval gates before autonomy reaches production.
An agent does not need shell access to cause damage. Give it an HTTP tool, a broad service token, and a user-controlled document, and it can be tricked into calling an internal host, uploading data, or triggering a real workflow.
Egress control is the boundary between “the model proposed a request” and “the network actually sent it.” Put that boundary in deterministic infrastructure. A system prompt is not a firewall.
Start With Deny by Default
Production agents should be unable to open arbitrary URLs. Define named destinations with exact schemes, hosts, ports, and path patterns. Resolve DNS in the trusted executor, reject private and link-local ranges, and re-check every redirect.
const destinations = {
billing: {
origin: "https://api.stripe.com",
methods: ["GET", "POST"],
paths: [/^\/v1\/customers\//, /^\/v1\/payment_intents$/],
},
};
Do not accept a model-supplied hostname because it resembles an allowed one. Parse the URL, normalize it, reject embedded credentials and unusual ports, then compare structured fields. Block localhost, RFC1918 ranges, cloud metadata endpoints, and IPv6 equivalents unless a specific internal service is intentionally exposed through a controlled gateway.
Give Tools Capabilities, Not Credentials
The model should never see raw API keys. A tool adapter should hold a credential that is scoped to one tenant, operation set, and short lifetime. “Call CRM” is too broad; “read contact fields for tenant A” is a capability.
Separate read, create, update, and delete. Use distinct tool definitions and credentials where the provider supports them. For mutating calls, bind the requested resource to the authenticated tenant inside the adapter. Never trust the model to carry a correct tenantId from context.
Short-lived tokens reduce blast radius, but expiration alone is not authorization. Record which workflow minted the token, which destination it permits, and which user approval—if any—backs the action.
Validate the Entire Request
An allowed host can still receive a dangerous payload. Validate method, path, query parameters, headers, content type, body schema, byte size, and field-level sensitivity.
const CreateTicket = z.object({
subject: z.string().max(160),
body: z.string().max(8_000),
requesterId: z.string().uuid(),
}).strict();
Strip model-created authorization headers. Reject unknown fields on consequential operations. Limit file types and decompressed size. If the agent can send email or webhook payloads, prevent it from choosing arbitrary recipients without an explicit policy check.
Responses need controls too. Cap bytes, timeouts, redirects, and MIME types. Treat returned text as untrusted data so a tool response cannot grant new authority through prompt injection.
Put Risky Transitions Behind Approval
Not every request deserves a human prompt. Reading a public documentation page is different from exporting a customer list or posting a refund.
Classify actions by destination, data sensitivity, reversibility, and financial impact. Permit low-risk reads automatically. Require approval for new recipients, bulk exports, credential changes, payments, publication, and destructive operations. The approval screen should show the resolved destination and exact effect, not the model’s friendly summary.
Use idempotency keys and preconditions after approval. A retry must not send the same payment twice, and an approval for one version of a record should not silently apply after that record changes.
Log Decisions, Not Secrets
For every attempted call, log the agent run, tool version, policy decision, normalized destination, operation, tenant, request digest, approval identity, response class, and latency. Redact tokens, sensitive payloads, and personal data.
Measure denied calls, redirect blocks, private-address attempts, approval rates, and policy-rule matches. A sudden rise in denied egress may reveal prompt injection, a broken planner, or a newly required destination.
Test the Boundary Like an Attacker
Ship regression cases for alternate IP encodings, DNS rebinding, redirect chains, punycode, trailing dots, user-info URLs, oversized bodies, cross-tenant IDs, hidden form fields, and untrusted instructions embedded in tool results.
The winning architecture is deliberately boring: named tools, tiny credentials, strict schemas, fixed destinations, explicit approvals, and complete audit trails. The agent can be creative inside the task. The network boundary cannot.
> Want more like this?
Get the best AI insights delivered weekly.
By subscribing, you agree to our Privacy Policy. You can unsubscribe at any time.
> Related Articles
AI Agent State Snapshots: Resume Long Jobs Without Repeating Side Effects
Durable agents need more than chat history. Snapshot plans, tool results, permissions, and idempotency state so a crash can resume safely instead of replaying the world.
Embedding Model Migration: Change Vectors Without Breaking Search
Embedding upgrades change the geometry of your index. Use versioned vectors, dual writes, shadow queries, and measured cutover instead of mixing incompatible representations.
LLM Request Coalescing: Stop Paying Twice for the Same Answer
When identical LLM requests arrive together, single-flight execution can collapse them into one upstream call—if cache keys, streaming, failures, and tenant boundaries are designed correctly.
Tags
> Stay in the loop
Weekly AI tools & insights.