SSRF (server-side request forgery)
You let a user hand your server a URL to fetch, and they point it at your own internal network instead.
See it
What it is
Any feature where a user hands you a URL and your server goes and fetches it: link previews, 'import from URL', webhook endpoints, avatar by image link, PDF and screenshot renderers, XML parsers that resolve external entities. The problem is where your server sits. It is inside the network, past the firewall, holding credentials, so it can reach things the attacker cannot: admin dashboards on localhost, internal APIs, the Redis box, and above all the cloud metadata service at 169.254.169.254, which will happily hand over instance credentials. That is the Capital One breach in one sentence.
Defend at the network layer as much as the code layer. Keep a strict allowlist of schemes (http and https only, no file://, gopher://, ftp://) and, where the feature permits, of hostnames. Resolve the hostname yourself, reject any result in private, loopback, or link-local ranges, then connect to that resolved address. Do not follow redirects automatically; follow them one hop at a time and re-validate each. Route outbound fetches through a proxy with its own egress rules, and require IMDSv2 so the metadata endpoint needs a header a blind fetch cannot set.
Gotcha: validating the URL string is not enough, because the danger is in what it resolves to at connect time. An attacker-controlled hostname can point at 127.0.0.1, or pass your check and then flip to an internal IP on the second lookup (DNS rebinding), or 302 you there mid-request. Second gotcha: blind SSRF returns nothing to the attacker and is still dangerous, since POSTing to an internal endpoint that deletes something needs no response at all.
Ask AI for it
Audit this codebase for SSRF and fix it. Find every place a URL from a user, a webhook config, or a stored record is fetched server side, and route all of them through one hardened fetch helper. That helper must: allow only http and https, reject credentials in the URL, resolve the hostname and refuse any address in loopback, private, link-local, or cloud metadata ranges (including 169.254.169.254 and ::1), connect to the resolved IP, disable automatic redirect following and re-validate every hop, and apply a short timeout plus a response size cap. Where the destination set is known, take a hostname allowlist instead. Add tests covering localhost, 127.0.0.1, 0.0.0.0, a private 10.x address, the metadata IP, file:// and a public URL that redirects to localhost.