Understanding SSRF — a defensive primer

Server-Side Request Forgery (SSRF) is one of the most reported vulnerability classes in modern web stacks. This post explains what it is, the canonical exploit shape, and three defensive layers you can ship today.

What is SSRF?

SSRF tricks a server into making an HTTP request it shouldn't — typically to internal infrastructure (RFC1918 networks, link-local cloud metadata, internal service discovery). The attacker controls the destination URL but executes the call from the server's network perspective, bypassing firewalls.

Vulnerable pattern

The canonical anti-pattern: a URL parameter is fetched server-side without origin validation.

// BAD — never write code like this in production.
app.get('/fetch', async (req, res) => {
  const target = req.query.url;
  const upstream = await fetch(target);
  res.send(await upstream.text());
});

An attacker calls /fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ and exfiltrates the EC2 instance role credentials.

Real-world payload shapes

Researchers see these patterns in the wild:

http://127.0.0.1:6379/INFO        # Redis pivot
http://localhost:9200/_cluster/   # Elasticsearch read
http://[::1]:5984/_all_dbs        # CouchDB enumeration
http://169.254.169.254/...        # AWS / Azure / GCP metadata
gopher://internal-srv:25/...      # SMTP smuggling
file:///etc/passwd                # Local file disclosure
⚠️ These are illustrative — none of the code in this post should be deployed. The point is recognition, not exploitation.

Three defensive layers

  1. Block outbound RFC1918 + link-local from untrusted callers. Use an egress proxy with an allowlist of known-safe destinations. Reject 127/8, 10/8, 172.16/12, 192.168/16, 169.254/16, and IPv6 unique-local prefixes.
  2. Validate URLs server-side, not just on the client. Resolve the hostname to its IP, check that IP against your blocklist BEFORE making the request, and pin the resolved IP for the connection to avoid DNS-rebinding.
  3. Run fetch workers under a minimal IAM role with no read on metadata endpoints. Cloud providers now ship IMDSv2 by default — require the session token and disable v1 entirely.

Further reading