I still remember the first time I saw an SSRF bug get exploited in something we ran ourselves. It wasn't a sophisticated zero-day. It was an image upload feature that let users submit a URL instead of a file, and our server dutifully fetched whatever URL it was given. Someone pointed it at our cloud provider's metadata endpoint and walked away with temporary credentials. No malware, no phishing, just a server doing exactly what it was told to do by a request it should never have trusted.
What It Is
Server-Side Request Forgery is a vulnerability class where an attacker manipulates a server into making network requests on their behalf, to destinations the attacker chooses rather than the destinations the application intended. The server becomes an unwitting proxy. It has network access, credentials, and trust relationships that the attacker doesn't have directly, and SSRF lets them borrow all of it.
The core ingredient is almost always the same: some piece of your application accepts a URL, hostname, or IP address as user input, and then uses it to make an outbound request. Webhook configuration fields, "import from URL" features, PDF generators that render remote HTML, image proxies, link preview generators, and API integrations that fetch data from a partner-supplied endpoint are all classic entry points. Anywhere your backend reaches out to a destination that a user can influence, you have a candidate for SSRF.
What makes it dangerous isn't the request itself. It's the position the server occupies on the network. A request from a user's browser to an internal admin panel on 10.0.0.0/8 just fails, because the browser can't route there. A request from your application server, sitting inside the VPC with the internal panel, succeeds just fine.
How It Works
The mechanics are usually depressingly simple. Say you run a service at sw-infrarunbook-01 that lets customers register a webhook URL to receive event notifications. The registration form takes a URL, and later your worker process does something like:
POST /api/webhooks/register HTTP/1.1
Host: solvethenetwork.com
Content-Type: application/json
{
"callback_url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
}
If there's no validation on that URL beyond "is it a syntactically valid URL," your worker will happily send a request to the cloud metadata service and, depending on the platform, hand back temporary IAM credentials in the response body. Those credentials get forwarded to the attacker as the "webhook payload." That's SSRF against cloud metadata, and it's the single most common real-world SSRF outcome I've seen in incident writeups over the last several years.
It's not limited to metadata endpoints, though. The same technique reaches internal services that were never meant to be internet-facing: an internal Redis instance on 192.168.1.50:6379, a Kubernetes API server on a cluster-internal address, an internal Jenkins or Grafana dashboard on 172.16.0.0/12 that has no authentication because "it's only reachable from inside the network." SSRF erases that assumption. If your application server can reach it, so can the attacker, through your application server.
There's also a subtler variant worth understanding: blind SSRF. The attacker doesn't get the response body back directly, but they can still cause the request to happen, and infer things from timing differences or side effects. A blind SSRF against an internal port scanner setup, for instance, can still be used to map which internal hosts and ports respond, purely by observing how long the request takes to fail versus succeed.
Attackers have gotten creative with bypasses too. Blocklisting "localhost" doesn't stop
http://127.0.0.1,
http://0.0.0.0,
http://[::1], or the decimal IP representation
http://2130706433, all of which resolve to the loopback address. DNS rebinding is another one: the attacker's domain resolves to a public IP during validation, then to an internal IP by the time the actual request fires, because DNS TTLs and validation timing don't line up. Redirects are a favorite too — the URL passes validation because it points somewhere benign, but the server follows a 302 redirect to an internal address that was never checked.
Why It Matters
SSRF matters because it collapses the boundary between "internet-facing" and "internal-only" that a lot of infrastructure security still quietly depends on. I've audited plenty of environments where the internal network segmentation was treated as a real security control, not just a convenience. Services with no authentication, admin panels with default credentials, metadata APIs with no request signing. All of that was fine as long as nothing on the public side could reach it. SSRF is exactly the crack that assumption falls through.
In cloud environments specifically, the blast radius is often worse than people expect. Cloud metadata services exist precisely to hand out credentials to whatever is running on the instance, no authentication required, because the assumption is that only the instance's own processes can reach that address. An SSRF bug turns that convenience feature into a credential vending machine for attackers. Depending on the IAM role attached to the instance, that can mean read access to storage buckets, the ability to spin up new resources, or in badly configured setups, near-total control of the cloud account.
It also matters because SSRF is frequently the first domino, not the whole chain. It rarely shows up alone in a serious breach. It's the pivot point: get SSRF, use it to read metadata credentials, use those credentials to enumerate more infrastructure, use that access to find the actual target. Treating SSRF as a low-severity "the server made an extra HTTP request" bug badly underestimates what it enables downstream.
Real-World Examples
The most cited public example is the 2019 breach at a major US financial institution, where a misconfigured web application firewall allowed a request that exploited SSRF to reach the AWS metadata service, retrieved temporary credentials, and used them to access and exfiltrate data from storage buckets containing over a hundred million customer records. The SSRF itself was almost incidental in complexity — a header manipulation through a reverse proxy — but the metadata credential access is what turned it into one of the largest breaches of that year.
I've also seen this pattern play out at much smaller scale in ordinary SaaS products. A "generate PDF from this webpage" feature that used a headless browser to render arbitrary URLs turned into an internal network scanner, because nothing stopped a user from pointing it at internal IP ranges and reading response timing or even rendered content if the internal service returned HTML. Link unfurling features (the kind that generate a preview card when you paste a URL into a chat app) have had the same issue repeatedly across different products — fetch the URL server-side to grab title and image metadata, no validation on where that URL is allowed to point.
Another pattern worth knowing: image processing pipelines that accept a remote URL for the source image, then pass that straight into a library like ImageMagick or a custom fetcher. These have been used not just for SSRF but chained with format-specific parsing bugs, because the fetched "image" doesn't actually have to be an image at all until the server tries to parse it.
Common Misconceptions
The most common misconception I run into is "we're not exposing an internal service directly to the internet, so we're fine." SSRF doesn't require you to expose anything directly. It requires exactly one feature that makes outbound requests based on user-controlled input, anywhere in your stack, including third-party libraries and background workers that nobody thinks of as "internet facing."
Another one: "we validate the URL with a regex that blocks internal IP ranges, so we're covered." Regex blocklists against IP ranges are notoriously easy to bypass through alternate IP encodings, IPv6 forms, redirects, and DNS rebinding, as covered above. I've reviewed more than one "secure" implementation that blocked
10.,
172.16., and
192.168.as string prefixes and missed
0177.0.0.1(octal loopback) entirely.
People also assume SSRF is only a problem for HTTP fetchers. It shows up in XML parsers that resolve external entities, in PDF generators, in webhook systems, in any library that does
fetch,
curl, or DNS resolution against user input, including things like image libraries resolving font URLs embedded in an SVG.
Last one, and it's the one that bites teams the hardest: "our cloud provider handles this for us." Some providers have moved to IMDSv2 or equivalent token-based metadata access specifically because SSRF against metadata endpoints was so common, and that's a genuinely good mitigation. But it's a mitigation for one specific SSRF target, not a fix for the underlying vulnerability in your application. You can still SSRF your way into internal services, other cloud APIs, and anything else reachable from that network position.
How to Prevent It
Start with allowlisting, not blocklisting. If your application only ever needs to fetch from a known, small set of destinations, enforce that explicitly rather than trying to enumerate everything that's dangerous. If user-supplied URLs are unavoidable, resolve the hostname yourself, validate the resolved IP against private ranges (RFC 1918 space, loopback, link-local including 169.254.0.0/16), and then connect to that validated IP directly rather than letting the HTTP client re-resolve DNS at request time, which is what opens the door to rebinding attacks.
Disallowed destination ranges (non-exhaustive):
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
127.0.0.0/8
169.254.0.0/16
::1/128
fc00::/7
Disable redirect following on outbound requests initiated from user input, or if you must follow redirects, re-validate the destination at each hop rather than trusting the first check. Set a strict timeout and response size limit on any server-initiated fetch, since these also double as basic protections against abuse even outside the SSRF context.
At the network layer, put egress filtering in place so that application servers can only reach the specific external endpoints they legitimately need, and cannot reach internal management interfaces, internal databases, or other internal services by default. This is the control that limits blast radius when a code-level validation bypass inevitably gets found later. Segment the network so that the servers handling user-facing fetch features sit in a position where reaching sensitive internal infrastructure requires an explicit, audited exception, not the default network path.
For cloud metadata specifically, move to the token-based metadata service version your provider offers, and set the hop limit low enough that requests proxied through an application won't reach it (a hop limit of 1 stops a request that's been forwarded through your application server, since it adds a hop). Don't treat this as sufficient on its own, but it closes off the single most common SSRF payoff.
Finally, log and alert on outbound requests from server-side fetchers that target private IP ranges or fail DNS resolution in suspicious ways. In my experience, teams that catch SSRF early are the ones watching their own egress traffic, not the ones relying purely on input validation at the code layer. Defense in depth here isn't a cliché, it's the only thing that reliably works, because any single validation layer will eventually have a bypass someone finds.
