GraphNode
Back to OWASP Top 10 hub
OWASP A10

OWASP A10:2021 Server-Side Request Forgery (SSRF) Explained

| 11 min read |GraphNode Research

TL;DR

A10:2021 Server-Side Request Forgery (SSRF) is the OWASP Top 10 category for vulnerabilities where a server makes an HTTP request to a URL controlled by an attacker, often pivoting into internal networks or cloud metadata services. It was new to the Top 10 in 2021, promoted largely on the back of the Capital One 2019 breach, where SSRF chained to AWS instance metadata exposed roughly 106 million records. The primary CWE is CWE-918. Detection is exactly the use case data flow SAST exists for — user input flowing into an HTTP client call across method boundaries is the canonical taint pattern. Prevention combines URL allowlisting, blocking private and cloud-metadata IP ranges, IMDSv2 on AWS, and egress proxies with policy.

Server-Side Request Forgery jumped to the OWASP Top 10 in 2021 after years on the watchlist. The vulnerability class is older than the category: SSRF write-ups appeared in the late 2000s and early 2010s, and bug bounty reports normalized the term well before OWASP made it official. What changed in 2021 was the cloud-era impact profile. Cloud workloads expose IAM credentials through instance metadata services on link-local addresses, and any application that can be coerced into making an HTTP request to a metadata URL becomes a credential-exfiltration tool. The risk class went from "interesting internal-network pivot" to "category-defining cloud-takeover chain."

The 2019 Capital One breach was the inflection point. An SSRF in a misconfigured web application firewall let the attacker reach the AWS instance metadata endpoint at 169.254.169.254, retrieve credentials for the IAM role attached to the host, and use those credentials to enumerate and exfiltrate data from S3 — exposing roughly 106 million records. The chain became the textbook reference for why SSRF deserves Top 10 status in cloud environments. This guide walks through what SSRF is, why the cloud era made it worse, the patterns that show up in real applications, the high-profile incidents, the CWE mapping, and where data flow SAST is the strongest detection layer for the category.

What SSRF Is

Server-Side Request Forgery is the class of vulnerability where an application accepts a URL from a user, fetches that URL on the server side, and either returns the response to the user or acts on it server-side. The defect is that the application uses the user-supplied URL without sufficient validation — so the attacker can point the server at addresses the attacker cannot reach directly: internal services bound to localhost, private IP ranges inside the organization's network, cloud metadata endpoints, or services exposed only inside a Kubernetes cluster.

The core pattern is uncomplicated. The application has a feature that needs to fetch a remote resource — an image to thumbnail, a webhook to deliver, a URL to render as a PDF, a feed to import. The handler reads a URL from the request, calls an HTTP client, and returns the result. If there is no allow-list, no destination filter, and no validation that strips dangerous targets, the same handler will happily fetch http://localhost:6379, http://169.254.169.254/latest/meta-data/, or http://internal-admin.svc.cluster.local. The server has network access the attacker does not, and the application becomes a proxy that grants it.

Two variants matter. In-band SSRF returns the response of the forged request to the attacker — useful for reading internal pages and metadata service responses. Blind SSRF does not return the response but still triggers the request — useful for hitting endpoints that have side effects (causing internal services to act on the attacker's behalf, sending data via email, or scanning internal ports by inferring open or closed status from response timing). Both are in scope for A10.

Why SSRF Got Worse in the Cloud Era

Pre-cloud, SSRF was an internal-pivot vulnerability. The exploit ceiling was usually limited to whatever internal services happened to listen on private IPs without authentication — admin dashboards, database web consoles, monitoring endpoints. Painful but bounded. Cloud workloads changed the math by introducing a single, predictable HTTP endpoint that returns workload identity credentials.

AWS instance metadata service. Every EC2 instance, by default, exposes a metadata HTTP service at 169.254.169.254. That service returns information about the instance — and, critically, returns short-lived credentials for the IAM role attached to the instance. An attacker who can coerce the instance into making an HTTP GET to http://169.254.169.254/latest/meta-data/iam/security-credentials/ retrieves those credentials and inherits the IAM role's permissions. Whatever the role can do (read S3 buckets, query RDS, invoke Lambda, list KMS keys), the attacker can do.

Azure, GCP, and Kubernetes equivalents. Azure exposes a metadata service at 169.254.169.254/metadata/identity/oauth2/token with a required header for retrieval. GCP exposes metadata.google.com with a required Metadata-Flavor: Google header. Kubernetes service accounts mount a token file inside the pod that any process running as the workload can read; SSRF inside a pod that lets an attacker reach kubernetes.default.svc opens an entirely separate attack surface against the API server. Each provider has its own variant; all of them are reachable from inside the workload, and SSRF is the bridge.

The result is the SSRF-to-cloud-takeover chain: a single application bug becomes a credential leak, the credentials inherit broad IAM permissions, and the attacker enumerates and exfiltrates data from anything the role can touch. The category jumped to the OWASP Top 10 because this chain became common enough — and damaging enough — to warrant top-level attention.

Common Patterns

Webhooks pointing to internal addresses. A SaaS feature that lets customers register webhook URLs for event notifications. The application POSTs to the URL when events fire. If the application does not validate the destination, a customer (or an attacker) can register a webhook pointing at an internal admin endpoint, the metadata service, or a private IP — and trigger events to coerce the application into making the request.

Image URL fetching with no allow-list. Profile-picture upload by URL, link previews in a chat application, social-media unfurling, and "fetch this avatar from a third-party service" features all involve the application making an HTTP request to a user-supplied URL. Without strict allow-listing of permitted hosts, every one of these is an SSRF primitive.

PDF generation from URL. "Render this URL as a PDF for the report" features that pass the URL to a headless browser. The headless browser inherits the network position of the application server. Without restrictions, the URL can target internal services, metadata endpoints, or local file URLs, depending on the browser configuration.

OAuth callback URL manipulation. Some OAuth implementations allow open redirect or insufficiently validate callback URLs, which can be combined with SSRF when the server fetches the callback. The combination is dangerous when the callback URL is fetched server-side rather than just redirected to client-side.

URL preview features. Slack-style link unfurling, where the application fetches a posted URL to extract title, description, and preview image. The handler runs on the application server with the application's network reach. Without filtering, posting an internal URL gets it fetched and the resulting preview returned to the attacker.

XXE leading to SSRF. XML External Entity processing that lets an XML document include external resources can be used to make the parser fetch arbitrary URLs server-side. XXE is its own category but is often a stepping stone to SSRF when the parser is configured permissively.

Real-World Incidents

Capital One (2019). The category-defining case. A misconfigured web application firewall in front of a Capital One application contained an SSRF vulnerability. An external attacker exploited it to coerce the host into making an HTTP request to the AWS instance metadata service at 169.254.169.254, retrieved credentials for the IAM role attached to the host, and used those credentials to list and download data from S3 buckets the role was permitted to access. Approximately 106 million records were exposed. The chain — SSRF to metadata to IAM credentials to S3 enumeration to exfiltration — is the reference architecture for cloud SSRF impact, and the incident is the largest single reason A10 sits on the 2021 Top 10.

GitLab CVE-2021-22214. An unauthenticated SSRF vulnerability in GitLab's CI/CD lint endpoint allowed an attacker to coerce the GitLab server into making arbitrary HTTP requests. In cloud-deployed GitLab instances the chain extended to the cloud metadata service in the standard way. The vulnerability was patched, but it is a clean reference case: a feature designed to validate user-supplied configuration accepted a URL field and fetched it server-side, exactly the pattern A10 describes.

Atlassian Confluence CVE-2022-26134. The Confluence OGNL injection vulnerability that drove the well-publicized June 2022 patching scramble was primarily a remote code execution bug rather than a pure SSRF, but the post-exploitation behavior in many of the observed incidents involved using the compromised Confluence instance as an SSRF pivot — making outbound HTTP requests to internal targets and to cloud metadata services. The incident illustrates the overlap between RCE and SSRF in real exploitation chains: once an attacker has code execution, they often use the host to make the HTTP requests the SSRF would have made directly.

Relevant CWE Mapping

A10:2021 maps cleanly to a single primary CWE entry, which is unusual for a Top 10 category — most aggregate dozens of underlying CWEs. The narrowness reflects the specificity of the pattern.

CWETitleWhere It Shows Up
CWE-918Server-Side Request Forgery (SSRF)User-supplied URL flowing into a server-side HTTP client without destination validation
CWE-352Cross-Site Request Forgery (CSRF)Different category — often confused with SSRF because of the name; CSRF is a client-side / browser issue

CWE-918 is the entire substantive mapping. The CSRF entry is included only to head off the common name confusion: CSRF (CWE-352) is the browser-level attack where a malicious site induces the victim's browser to make a state-changing request to a target site the victim is authenticated against. SSRF is the server-side request the attacker induces through a vulnerable application. Same word "request forgery," different attack surface, different defense.

Detection: SAST Data Flow Analysis Is the Primary Tool

SSRF is the textbook use case for taint-aware static analysis. The vulnerability shape is precisely the data flow pattern interprocedural analysis is built to find: a tainted source (an HTTP parameter, a request body field, a query string value containing a URL) flows through some number of intermediate function calls and reaches a sink (an HTTP client constructor or fetch call). If the path contains no validation against an allow-list of permitted destinations, the path is a candidate finding.

The sinks are framework-specific but well-enumerated. In .NET, HttpClient.GetAsync, HttpClient.PostAsync, WebClient.DownloadString, and WebRequest.Create. In Java, HttpURLConnection, Apache HttpClient, OkHttp, and Spring's RestTemplate and WebClient. In Python, urllib.request.urlopen, requests.get, and httpx.get. In Node, fetch, axios, node-fetch, and got. A serious SAST engine ships with sink models for each, and the rule packs trigger when a tainted URL parameter reaches any of them through a path with no validation.

The reason data flow analysis matters here — and pattern matching does not — is the multi-hop nature of real handlers. A request lands in a controller, the URL parameter is passed to a service, the service calls a helper, the helper finally invokes the HTTP client. Three or four function-boundary crossings is normal, and a regex linter that only sees one frame at a time misses the entire chain. Interprocedural taint propagation is the technique that follows the value across all of those calls. For more on why the technique matters and how it is implemented, see why data flow analysis matters. For the engine itself, see GraphNode SAST.

DAST and runtime layers complement SAST for SSRF but do not replace it. DAST can attempt to trigger SSRF by submitting payloads pointing at attacker-controlled servers and observing whether the application calls back, but this is bounded by what the crawler reaches and by whether the application returns enough signal to detect the attempt. Egress filtering at the network layer catches outbound requests that should not be made — but only if the filter is in place and correctly scoped.

Prevention

Allow-list destination URLs. The most effective control. Define the set of hosts the feature is allowed to reach, and reject anything else. Allow-listing is harder than deny-listing but is the only approach that catches new attack variants — IPv6, IPv4-mapped IPv6, wildcard DNS pointing at private IPs, decimal-encoded IPs, the entire bag of URL-parser tricks attackers use to slip past deny rules.

Deny private IP ranges. Block 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 (RFC 1918), 127.0.0.0/8 loopback, 169.254.0.0/16 link-local (which includes the cloud metadata addresses), and IPv6 equivalents. Resolve the destination hostname first and check the resolved IP, not the input string — DNS rebinding attacks specifically target post-resolution time-of-check-to-time-of-use gaps.

Deny cloud metadata addresses. Explicitly block 169.254.169.254, metadata.google.com, and the Azure metadata equivalents at the application layer regardless of network policy. Defense in depth: the network filter should also block these, but the application should refuse them on its own.

Parse and validate URLs properly. Use the platform's URL parser, then validate the parsed components — scheme, host, port — against the allow-list. Do not string-match the input; URL parsing is full of edge cases that string matching gets wrong. Disable URL schemes you do not need (file://, gopher://, dict://).

Use a separate egress proxy with policy. Route all outbound HTTP from the application tier through a proxy that enforces the allow-list at the network layer. This makes the policy a configuration concern instead of a per-handler code concern, and it survives bugs in individual handlers.

Use IMDSv2 on AWS. AWS Instance Metadata Service Version 2 requires a session token obtained via a PUT request and uses it as a header on subsequent GETs. Most basic SSRF primitives can only make GET requests with default headers, so IMDSv2 defeats them by construction. Set IMDSv2 to required on every EC2 instance and remove the IMDSv1 fallback.

Where GraphNode SAST Fits — Strong Detection Category

A10 is one of the categories GraphNode SAST is best positioned to detect. The interprocedural taint propagation engine is built precisely for the SSRF data flow shape: a URL value originating in user input — query string, request body field, header value — flows through any number of intermediate calls across function boundaries and reaches an HTTP client sink. The engine ships with sink models for the major HTTP client APIs across the supported language set, and the rule packs trigger when a tainted URL reaches any of them through a path that lacks an allow-list check.

What separates serious SSRF detection from pattern-matching alternatives is the ability to follow the value across multiple hops without losing precision. A controller method that receives a URL, hands it to a service method, which hands it to a helper, which finally invokes an HTTP client, is the normal shape of real handlers. Single-frame pattern matchers see four unrelated functions; data flow analysis sees one chain that needs an allow-list somewhere along the way. The technical foundation is described in more detail in why data flow analysis matters; for the broader category context across all ten OWASP entries, see the OWASP Top 10 hub.

Frequently Asked Questions

What is SSRF?

Server-Side Request Forgery (SSRF) is the class of vulnerability where an application accepts a URL from a user, fetches that URL on the server side, and uses or returns the response without validating the destination. The attacker uses the application as a proxy to reach addresses they cannot reach directly: internal services, private IP ranges, or cloud metadata endpoints. SSRF is the OWASP A10:2021 category and maps to CWE-918. It became a top-level OWASP category in 2021 largely because of the Capital One 2019 breach, where SSRF chained to AWS instance metadata exposed roughly 106 million records.

Why was SSRF promoted to the OWASP Top 10 in 2021?

SSRF existed as a vulnerability class for years before 2021, but the cloud era made the impact profile dramatically worse. Cloud workloads expose IAM credentials through metadata HTTP services on link-local addresses (169.254.169.254 on AWS, equivalent endpoints on Azure and GCP). Any application that can be coerced into making a request to a metadata URL becomes a credential exfiltration tool, and the credentials inherit whatever IAM permissions the workload has. The 2019 Capital One breach made this chain a category-defining incident, and OWASP added SSRF to the 2021 list partly on that basis.

What is the difference between SSRF and CSRF?

The names are similar but the attacks are unrelated. CSRF (Cross-Site Request Forgery, CWE-352) is a browser-level attack where a malicious website induces a victim's browser to make an authenticated state-changing request to a target site where the victim has a session. The defense is anti-CSRF tokens and SameSite cookies. SSRF (Server-Side Request Forgery, CWE-918) is a server-side attack where an attacker induces a vulnerable application to make an HTTP request the attacker chooses, typically to reach internal addresses. The defense is destination allow-listing, blocking private and metadata IPs, and IMDSv2 on AWS.

Can SAST detect SSRF?

SSRF is one of the strongest detection categories for taint-aware SAST. The vulnerability is exactly a data flow pattern: a user-supplied URL flows through some number of function calls and reaches an HTTP client sink without an allow-list check on the path. Interprocedural taint propagation traces the value across method boundaries and flags the path. Pattern-matching linters that only see one frame at a time miss the multi-hop cases that dominate real handlers; data flow analysis catches them. SAST is the primary detection layer for A10, complemented by DAST and network egress controls.

How does IMDSv2 prevent SSRF on AWS?

AWS Instance Metadata Service Version 2 requires a session token to read metadata. The token is obtained by sending a PUT request with a TTL header, and the returned token must be included as a header on subsequent GET requests for metadata. Most basic SSRF primitives can only induce the application to make GET requests with the application's default headers — they cannot easily make PUT requests or set arbitrary headers. IMDSv2 therefore defeats most SSRF chains by construction. Setting IMDSv2 to required on every EC2 instance, with no IMDSv1 fallback, is one of the most cost-effective controls for the SSRF-to-cloud-takeover chain.

Detect SSRF Before It Becomes a Cloud-Takeover Chain

GraphNode SAST traces user-supplied URLs through every method-boundary crossing into HTTP client sinks across 13+ languages, with deep interprocedural data flow analysis built for exactly the CWE-918 pattern.

Request Demo