Audit BenchAi
← All posts

How to Spot Server-Side Request Forgery (SSRF) in Code Review

·7 min read

Server-side request forgery happens when server code makes an outbound HTTP request to a destination that a user fully or partially controls. The danger isn't the request itself — it's that the request originates from inside your infrastructure, with your server's network position and sometimes its credentials, letting an attacker use your own backend as a proxy into places the public internet was never supposed to reach.

Where SSRF hides in ordinary features

  • Webhook URL fields — anywhere a user configures a URL that your server will later call.
  • "Import from URL" or link-preview and unfurling features that fetch a page to extract a title, image, or metadata.
  • PDF or image generation that renders a user-supplied URL server-side.
  • Logo or avatar fetching during signup or OAuth flows, where a URL is pulled from an external profile.
  • Any server-side rendering step that resolves a link the user provided before displaying it.

Why cloud metadata endpoints raise the stakes

Most cloud providers expose an instance metadata service at a fixed link-local address (commonly 169.254.169.254) that hands back information about the running instance — and, in misconfigured setups, temporary credentials for whatever role the instance runs as. If server-side code can be tricked into making a request to that address, SSRF stops being an information-disclosure curiosity and becomes a path to full credential theft and lateral movement inside the cloud account. This single fact is why SSRF is treated far more seriously today than its description — "the server fetched a URL it shouldn't have" — might initially suggest.

Blocklists are the wrong control

Checking a user-supplied URL against a list of forbidden strings like localhost or 127.0.0.1feels like a fix and isn't one. Attackers route around it with alternate IP encodings (decimal, octal, or IPv6-mapped forms of a loopback address), DNS names that resolve to an internal address only at request time (DNS rebinding), and redirects — a URL that passes validation, then responds with a redirect to an internal address that the HTTP client follows without re-checking.

What a real fix looks like

  1. Validate against an explicit allow list of expected hosts wherever the set of legitimate destinations is known in advance, rather than trying to block everything bad.
  2. Resolve the DNS name and check the resulting IP address is not in a private, loopback, or link-local range before opening the connection — checking the hostname string alone is not enough.
  3. Disable automatic redirect-following on outbound requests, or re-validate the destination after every redirect hop rather than trusting the first check.
  4. Add network-level egress restrictions as defense in depth, so that even a missed case in application code can't reach internal services or the metadata endpoint.

Checklist for reviewing code that makes outbound requests

  • Every server-side fetch, image download, or webhook delivery that uses a user-supplied URL is traced end to end for validation.
  • Validation happens against the resolved IP address, not just the hostname string.
  • Redirects are either disabled or re-validated on each hop.
  • Features that don't need to support arbitrary destinations use an allow list instead of a blocklist.

Read about reviewing API changes for security risk →

See how to review rate limiting and abuse prevention →