Server-Side Request Forgery (SSRF) was added to the OWASP Top 10 in 2021, reflecting its growing prevalence in modern cloud-hosted web applications. The vulnerability is deceptively simple: an attacker controls a URL that your server fetches, and uses that control to reach systems that should be inaccessible from the outside — internal APIs, cloud infrastructure metadata, and services protected by firewalls.

How SSRF Works

Many legitimate web application features involve server-side HTTP requests: importing content from a URL, fetching an Open Graph preview for a link, triggering a webhook, loading a remote avatar, or querying an external API. When these features accept user-controlled URLs without validation, SSRF is possible.

The simplest example:

GET /api/fetch-preview?url=https://example.com/image.jpg

If the server fetches the URL and returns the content, an attacker can substitute:

GET /api/fetch-preview?url=http://169.254.169.254/latest/meta-data/

169.254.169.254 is the AWS Instance Metadata Service (IMDS) — accessible only from within an EC2 instance, not from the internet. From the browser, this request would fail. From the server, it succeeds. The metadata service returns IAM credentials, VPC configuration, and other sensitive cloud infrastructure data.

High-Value SSRF Targets

The Capital One breach of 2019 — exposing data of over 100 million customers — was executed through SSRF on an AWS EC2 instance, allowing the attacker to retrieve IAM credentials from the metadata service.

Blind SSRF

In many cases, the server does not return the response of the internal request to the attacker — but the request still happens. This "blind SSRF" can be detected by using a URL pointing to an attacker-controlled server and monitoring for incoming connections:

GET /api/webhook-test?url=https://attacker-burp-collaborator.net/probe

If the attacker's server receives a hit, SSRF is confirmed even though the response was not reflected. Blind SSRF can be used for internal network scanning and, in some environments, for reaching internal APIs that do not return their output in errors.

Prevention

URL Allowlisting (Primary Defense)

The most robust prevention: only allow requests to a pre-approved list of domains or IP ranges. Reject everything else before the request is made.

ALLOWED_HOSTS = {'api.trusted-service.com', 'cdn.yoursite.com'}

from urllib.parse import urlparse

def safe_fetch(url):
    parsed = urlparse(url)
    if parsed.hostname not in ALLOWED_HOSTS:
        raise ValueError(f"Host not allowed: {parsed.hostname}")
    # Now safe to fetch

Block Private IP Ranges

If an allowlist is not feasible, at minimum block requests to private and link-local IP ranges before the request executes. Resolve the hostname first, then check the resolved IP:

import ipaddress, socket

def is_private_ip(hostname):
    try:
        ip = ipaddress.ip_address(socket.gethostbyname(hostname))
        return ip.is_private or ip.is_link_local or ip.is_loopback or ip.is_reserved
    except Exception:
        return True  # Block on error

if is_private_ip(urlparse(url).hostname):
    abort(400, "Internal URLs are not permitted")

Note the DNS rebinding risk: a hostname can resolve to a public IP during the check and to a private IP during the actual request. Use a dedicated DNS resolver that pins the resolved IP for the lifetime of the connection.

Disable Redirects

HTTP redirects can be used to bypass IP checks: the initial URL points to a public server that responds with a redirect to 169.254.169.254. Disable automatic redirect following in your HTTP client:

# Python requests
response = requests.get(url, allow_redirects=False, timeout=5)

IMDSv2 on AWS

On AWS, enable IMDSv2 (token-based metadata access) on all EC2 instances. IMDSv2 requires a PUT request to obtain a session token before metadata can be read — this extra step prevents simple SSRF from retrieving credentials, as the attacker's request will not include the token.

Detecting SSRF in Your Application

Review every feature that makes outbound HTTP requests: webhook handlers, URL preview generators, PDF generators that render remote URLs, image proxy services, import-from-URL features. For each, ask: is the URL fully user-controlled? Can the user reach internal IP ranges through it? If yes, apply the controls above.