Modern web applications regularly make outbound HTTP requests on behalf of users. A feature that imports an image from a URL, generates a preview of a webpage, fetches a remote document, or validates a webhook endpoint all have one thing in common: the server is making a network request, and something the user supplied is influencing where that request goes.
That architecture is where Server-Side Request Forgery begins.
The Server Makes the Request, Not You
When a user provides a URL to an application, the request flow looks like this:
User
↓
Web Application
↓
Server fetches URL
↓
example.com
From the network's perspective, the outbound connection comes from the server, not the user's browser. The user's browser sends one request to the application. The application's server sends a separate request to the destination.
This distinction matters more than it first appears.
The vulnerability isn't that servers can make HTTP requests. That's normal and necessary. The vulnerability is when an attacker can control where those requests go, and the server can reach destinations the attacker cannot.
The Trust Boundary
Every server operates within a network context. From that context, it may have access to resources that are completely unreachable from the public internet:
- services bound to localhost
- internal APIs on private networks
- database management interfaces
- administrative dashboards
- cloud infrastructure endpoints An attacker sitting on the internet cannot reach these directly. The server can.
Direct access:
Attacker ──────────X──────────→ Internal Service
no path
SSRF:
Attacker
↓
Vulnerable Web Application
↓
Server
↓
Internal Service
The application becomes an unintended proxy, using its own network position on the attacker's behalf. The attacker doesn't need a route to the internal service. The server already has one.
Why localhost Is Especially Interesting
localhost always refers to the machine making the request. When your browser navigates to localhost, it connects to your own machine. When a server makes a request to localhost, it connects to itself.
This means:
Attacker's browser → localhost → attacker's machine
Server → localhost → the server itself
These are completely different destinations. A server running a database management interface, an internal metrics service, or an administrative API on localhost may expose no port to the outside world. From the public internet, those services are invisible. From the server itself, they're immediately reachable.
The same applies to private IP ranges. Addresses in ranges like 10.0.0.0/8 or 192.168.0.0/16 are not routable from the internet. They can be reached from within the same private network. If the vulnerable application server sits in that network, so can SSRF-induced requests.
Why Validation Is Harder Than It Looks
The obvious developer response is to block dangerous destinations. Reject localhost. Reject private IP ranges. Return an error.
The difficulty is that a URL is not the same as a final network destination. Several things happen between accepting a URL and making the connection:
DNS resolution. A hostname in a URL eventually resolves to an IP address before the connection is made. Validating a hostname without considering where it resolves can leave gaps, because a hostname could resolve to a private address. A robust validation approach must consider the resolved destination, not just the original string.
Redirects. The application might validate an initial URL that appears safe, then follow a redirect to somewhere it shouldn't be. If the HTTP client blindly follows redirects without re-evaluating each destination against the security policy, the final connection may violate that policy even if the first URL appeared legitimate.
Both of these illustrate the same underlying principle: the security decision is about where the connection ultimately goes, not just what the original URL string looks like. Validation needs to account for the full path from URL to actual network destination.
Cloud Infrastructure and Metadata Services
SSRF became significantly more impactful as applications moved to cloud infrastructure. Cloud platforms commonly make instance metadata and configuration available through network endpoints accessible to workloads running within the environment.
A vulnerable application server running in a cloud environment may have access to these services from its network position. An attacker on the public internet does not. SSRF can bridge that gap.
The potential impact depends on what those services expose and how the environment is configured. Modern cloud platforms have introduced stronger default protections for metadata services, but SSRF reaching cloud infrastructure remains a high-severity finding because of what may be accessible.
What SSRF Can Expose
The impact of SSRF isn't uniform. It depends on what the vulnerable server can reach and what those destinations expose.
In practice, SSRF can allow an attacker to:
- interact with internal APIs that were never meant to be externally accessible
- reach administrative interfaces that assume requests come from trusted network locations
- discover internal services by probing addresses and observing responses
- access cloud infrastructure metadata depending on platform configuration SSRF does not automatically result in full system compromise. The impact is bounded by the server's network access and the services it can reach. But that boundary is often much wider than developers assume, because applications typically run with significant internal network access to do their legitimate work.
Defenses
Effective SSRF defense is an architectural question, not just a validation exercise.
Remove the capability if it's not needed. The strongest defense is not exposing a URL-fetching feature that accepts arbitrary user-controlled destinations. If the application only needs to fetch from a known set of services, hardcode those destinations rather than accepting URLs as input.
Allowlists over blocklists. If user-controlled URLs are genuinely necessary, prefer an explicit allowlist of permitted destinations over attempting to block every dangerous one. A blocklist requires knowing every dangerous destination in advance, including all the edge cases around address representations and resolution. An allowlist approach inverts this:
Blocklist: permit everything except known-bad destinations
Allowlist: deny everything except known-good destinations
Allowlists are easier to reason about and harder to bypass through edge cases.
Validate the actual resolved destination. URL validation needs to account for DNS resolution and check that the resolved IP falls within permitted ranges. Private addresses, loopback addresses, and link-local addresses should be outside the permitted range unless there's a specific reason to allow them.
Handle redirects carefully. If the HTTP client follows redirects, each redirect destination should be validated against the same destination policy as the original URL. Disabling redirects entirely is simpler if the use case doesn't require them.
Apply network-level egress controls. Application-level validation is one layer. Network segmentation and egress filtering add another. Even if the application has a bug, outbound access controls at the network level can limit what the server is capable of reaching. Defense in depth means that a single failed validation doesn't automatically expose the entire internal network.
Apply least privilege to cloud metadata access. Cloud environments should be configured with the platform's recommended protections to reduce what SSRF can reach within that infrastructure.
SSRF vs CSRF
Since CSRF has appeared in a previous article, the distinction is worth stating clearly.
CSRF abuses the victim's browser: the attacker tricks an authenticated user's browser into making a request the user didn't intend.
SSRF abuses the server's network position: the attacker influences where the server sends a request, using the server's access to reach destinations the attacker can't.
CSRF:
Attacker → victim's browser → target application
SSRF:
Attacker → vulnerable server → internal destination
Both involve forged requests. One uses the victim as the intermediary. The other uses the server.
SSRF isn't fundamentally about URLs. It's about who gets to decide where a trusted server can connect.
Servers have network access that internet users don't. Internal services, private infrastructure, and cloud metadata endpoints are often reachable from within the server's network while being invisible from outside. If an application allows untrusted input to influence outbound request destinations without enforcing a strong destination policy, the server's own network privileges become an attack surface.
The server isn't attacking itself. It's doing exactly what it was programmed to do: making a request. The vulnerability is allowing an untrusted party to decide where that request goes.
Top comments (0)