An SSRF attack — server-side request forgery — happens when an attacker gets your server to make an HTTP request to a destination the attacker chooses, letting them reach internal systems, cloud metadata, and services that were never exposed to the internet. The dangerous part of what is an SSRF attack is not that your app fetches a URL; it is that the request comes from inside your network, with your server's trust and network position, so firewalls and access controls that assume "external traffic is untrusted, internal traffic is fine" get bypassed entirely. This guide explains the mechanism with a clear SSRF example, then focuses on detection and defense. It stays conceptual — no working payloads against real targets.
What an SSRF attack is
SSRF is classified as CWE-918 and sits in the OWASP Top 10 (A10:2021). The setup is any feature where your application takes a URL, hostname, or address from a user and then makes a request to it: a webhook configuration, an "import from URL" feature, a link-preview generator, a PDF renderer that fetches images, an avatar-upload-by-URL. The vulnerability appears when the application fetches whatever the user supplies without validating where that request is actually going.
The reason it is so impactful is network position. Your server can usually reach things a random internet user cannot: internal admin panels on private IP ranges, databases, other microservices, and — most damaging in cloud environments — the instance metadata service.
A conceptual SSRF example
Consider a link-preview endpoint. A user submits a URL, the server fetches it to generate a thumbnail and title, and returns the preview. The intended use is public web pages:
POST /preview
{ "url": "https://example.com/article" }
In an SSRF attack example, the attacker instead submits a URL pointing at an internal address — a private-range host, localhost, or a cloud metadata endpoint. If the server blindly fetches it, the attacker now reads responses from services that were never meant to be reachable from outside. The application becomes a proxy into the internal network. That is the whole trick: the request originates from a trusted position, so internal services answer it.
The real-world reference point is the 2019 Capital One breach, where an SSRF vulnerability was used to reach the AWS instance metadata service and retrieve temporary credentials, which were then used to access data in S3. It remains the canonical illustration of why SSRF plus cloud metadata is a critical combination, and it is a large part of why AWS pushed IMDSv2 (which requires a session token and blocks the naive metadata fetch) as a mitigation.
Why blocklists do not work
The instinctive fix is to reject "bad" destinations — block 127.0.0.1, block 169.254.169.254, block 10.x. This fails, because the address space of "internal" is large and there are many ways to express the same destination. Attackers use decimal or hexadecimal IP encodings, alternate loopback addresses, DNS names that resolve to internal IPs, redirects from an allowed host to an internal one, and IPv6 representations. Every blocklist has gaps, and the gaps are exactly what SSRF research spends its time finding. Filtering the string the user typed is not the same as controlling where the request goes.
How to prevent an SSRF attack
Effective defense works on the request, not the input string. Layer these:
Allowlist destinations. If a feature only ever needs to reach a known set of hosts, allow exactly those and deny everything else. This is the strongest control and it is available more often than teams assume — most "fetch a URL" features have a narrow legitimate range.
Resolve, then validate, then pin. Where an open destination is genuinely required, resolve the hostname to an IP, reject the request if that IP is in a private, loopback, link-local, or reserved range, and then connect to the validated IP so a later DNS change cannot swap the target (this defeats DNS-rebinding). Do the check after resolution, not on the raw string.
import ipaddress, socket
def is_safe_destination(hostname):
ip = ipaddress.ip_address(socket.gethostbyname(hostname))
return not (ip.is_private or ip.is_loopback
or ip.is_link_local or ip.is_reserved)
Disable redirects, or re-validate each hop. An allowed host that redirects to an internal one bypasses a check that only ran on the first URL. Either disable automatic redirects on the fetch or run the destination validation on every hop.
Lock down the network egress. Defense in depth: the server making these requests should not be able to reach internal management interfaces or the metadata service in the first place. Enforce IMDSv2 in AWS, and use network policies so the fetching service can only egress to what it legitimately needs.
Never return raw responses. If the fetched content is reflected back to the user, return only what the feature needs (a title, a thumbnail) rather than the raw response body, so a successful SSRF leaks as little as possible.
Detecting SSRF in your code and traffic
To find SSRF risk before an attacker does, search for the pattern: any place a request destination is built from user input. Grep for HTTP-client calls (requests.get, fetch, HttpClient, curl) and trace their URL arguments back to see whether any originate from request data. A SAST scanner will flag many of these taint paths automatically, and a DAST scan can probe running endpoints by supplying internal-looking destinations and watching whether the server behaves differently — a strong signal that the request is actually being made. Combining static taint analysis with dynamic probing catches both the code that looks vulnerable and the endpoints that actually are. Our academy covers the taint-tracking approach in more depth.
FAQ
What is an SSRF attack in simple terms?
It is when an attacker makes your server send a request to a destination they choose. Because the request comes from your server's trusted network position, it can reach internal systems and cloud metadata that outsiders normally cannot.
What is a common SSRF example?
A link-preview or "import from URL" feature that fetches whatever URL a user submits. If the user points it at an internal address or a cloud metadata endpoint instead of a public page, the server fetches it and can leak internal data.
Why is SSRF so dangerous in the cloud?
Because cloud instance metadata services return temporary credentials to requests from the instance itself. An SSRF that reaches the metadata endpoint can retrieve those credentials, which is how the 2019 Capital One breach escalated. IMDSv2 mitigates the naive version of this.
How do you prevent SSRF attacks?
Allowlist destinations where possible; otherwise resolve the hostname, reject private and reserved IP ranges, and connect to the validated IP. Disable or re-validate redirects, restrict the server's network egress, enforce IMDSv2, and never reflect raw fetched responses back to the user.