SSRF examples are most useful when they show the full chain, not just the vulnerable line of code, because server-side request forgery is rarely the end goal on its own. It's a foothold that attackers use to reach something the application server can see but the internet can't: an internal admin panel, a cloud metadata endpoint, or a database that trusts requests from inside the network. This post walks through the common patterns with enough detail to recognize them in your own code.
What is SSRF, concretely?
Server-side request forgery happens when an application takes a URL, or a piece of a URL, from user input and uses it to make an outbound HTTP request from the server. The classic case is a "fetch remote image" or "webhook URL" feature: the server receives a URL, downloads whatever's there, and returns it or processes it. If the server will fetch any URL the user supplies, including internal, non-public addresses, the user has effectively gained the server's network position.
A minimal vulnerable example:
app.post("/fetch-avatar", async (req, res) => {
const response = await fetch(req.body.imageUrl);
const buffer = await response.arrayBuffer();
res.send(Buffer.from(buffer));
});
Nothing here restricts imageUrl to public, image-serving hosts. It'll fetch anything the server can reach.
How does cloud metadata theft work?
This is the most cited SSRF example because it's so consistently damaging. Cloud providers expose an instance metadata service at a fixed internal address, 169.254.169.254 on AWS, GCP, and Azure, that returns instance details and, critically, can return temporary IAM credentials if the instance role permits it. An attacker who finds an SSRF bug points the vulnerable request at that address:
POST /fetch-avatar
imageUrl=http://169.254.169.254/latest/meta-data/iam/security-credentials/my-role
If the response is returned to the attacker, or even just logged somewhere they can read, they now have valid temporary AWS credentials scoped to whatever permissions the instance role carries. This exact pattern was central to the 2019 Capital One breach, where an SSRF vulnerability in a misconfigured web application firewall was used to reach the metadata service and pull credentials that were then used to access S3 buckets. AWS's IMDSv2, which requires a session token obtained via a PUT request, was introduced largely in response to this class of attack, and it's worth confirming your infrastructure enforces it rather than falling back to IMDSv1.
How is SSRF used to scan internal networks?
Even without metadata access, SSRF gives an attacker a way to probe your internal network topology by observing response differences. If the vulnerable endpoint returns different errors, or different timing, for a reachable internal host versus an unreachable one, an attacker can enumerate internal IP ranges and ports:
imageUrl=http://10.0.1.5:6379/
imageUrl=http://10.0.1.5:8080/
imageUrl=http://10.0.1.5:22/
A response that hangs (open port, no HTTP response) versus one that errors immediately (closed port) is enough signal to map internal services blind. Once an internal admin panel or an unauthenticated internal API is located this way, the SSRF becomes a pivot point rather than an information leak.
Can SSRF lead to remote code execution?
Yes, when it reaches a service that itself has an unsafe operation reachable over its own protocol. A well-known chain: SSRF reaching an internal Redis instance with no authentication. Redis's protocol allows writing arbitrary keys, and several published techniques abuse the CONFIG SET and MODULE LOAD commands, or writing a cron file or SSH key via Redis's persistence mechanisms, to achieve code execution on the Redis host. The SSRF is the delivery mechanism; the actual vulnerability being exploited is the internal service's lack of authentication, but without the SSRF the attacker would never have reached it from outside.
Another chain worth knowing: SSRF against internal cloud API endpoints (like a Kubernetes API server left reachable without auth on the pod network) can be used to read secrets or schedule new pods, effectively full cluster compromise starting from a single unvalidated URL parameter.
How do you actually prevent SSRF?
Allowlisting the destination is the most reliable control: if your feature only ever needs to fetch from a small set of known domains, enforce that at the network layer, not just in application code, because DNS rebinding attacks can defeat a naive hostname check performed before the request is made. Validate the resolved IP address at connection time, and reject private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, link-local 169.254.0.0/16) unless there's a specific reason to allow them.
Network-level segmentation matters as much as code fixes. If the server making outbound requests on users' behalf has no route to your internal admin services or metadata endpoint in the first place, an SSRF bug in the code degrades from full compromise to a much smaller information leak. This is a case where defense in depth genuinely changes the blast radius, not just the theoretical risk. Egress firewall rules on the application tier, combined with input validation, catch most real-world SSRF attempts even when a code-level bug slips through review.
If you're building a program to catch this class of issue systematically, DAST scanning that actually attempts outbound requests to internal-looking addresses during a scan pass is a more direct test than code review alone, since it exercises the runtime behavior rather than inferring it from source.
FAQ
What's the simplest way to describe SSRF to a non-security engineer?
It's when your server can be tricked into making a network request on the attacker's behalf, to a destination the attacker chose, using the server's own network access and credentials.
Is SSRF only relevant to cloud-hosted applications?
No, but cloud metadata endpoints make the impact much higher because they can hand over live credentials. On-prem SSRF is still dangerous for internal network scanning and reaching unauthenticated internal services, just without the instant-credential-theft step.
Does using a URL allowlist fully solve SSRF?
It solves most of it if enforced correctly, but a naive implementation that checks the hostname before resolving DNS is vulnerable to DNS rebinding, where the hostname resolves to a public IP at check time and a private IP at request time. Validate the IP actually being connected to, not just the hostname string.
How is SSRF different from CSRF despite the similar name?
CSRF tricks a victim's browser into making a request using the victim's own session; SSRF tricks the server itself into making a request using the server's own network position and credentials. They target different actors entirely.