Vulnerabilities/Server-Side Request Forgery (SSRF)
Server-Side Request Forgery (SSRF)
Server-side request forgery happens when an application fetches a URL that a user controls, for a link preview, webhook, image import or PDF renderer, and the server's network position lets that request reach addresses the user never could: 127.0.0.1, private subnets, admin ports and the cloud metadata service at 169.254.169.254. Checks on the URL string, or on a DNS answer taken before the request, fail against IP encodings, redirects and DNS rebinding. The fix is the same everywhere: check the actual IP address at the moment the socket connects, allow only http and https, do not follow redirects or use an environment proxy, set timeouts and a body cap, and enforce IMDSv2. Pick your language below for the exact hook, vulnerable and fixed code, and the linters that catch it.
Plain English Explainer (ELI5)
A hotel lets guests ask the concierge to collect a parcel from any address in town. You write down the address of the hotel's own staff-only office upstairs, where the master keys hang. The concierge wears a staff badge, walks straight in and brings you the key box, because the form only asked for an address, never whether that address is outside the hotel. A server that fetches URLs for users works the same way: from inside the network it can reach 127.0.0.1, internal APIs and the cloud metadata service at 169.254.169.254. The fix is to check where the concierge actually arrives, not just the address on the form, and to refuse notes on the door that say 'go upstairs instead'.
Core Concepts & Subsystem Terms
- SSRF (CWE-918)
- A server-side component sends a network request to a destination that request data controls, so an outside user can make the server reach hosts and ports that only the server's network can reach.
- Cloud metadata service (IMDS)
- Cloud VMs expose instance credentials at
http://169.254.169.254/. IMDSv1 answers any GET; IMDSv2 requires a PUT for a session token and a hop limit, which blocks most SSRF. The 2019 Capital One breach read IAM keys through this service. - Allowlists that check the wrong thing
- Comparing the hostname string, a prefix or a regex misses
127.1,0x7f000001,[::ffff:127.0.0.1],user@hosttricks and redirects to internal URLs, and a check on the first DNS answer says nothing about the address the client later connects to. - DNS rebinding
- An attacker's DNS server answers the validation lookup with a public address and the HTTP client's own lookup a moment later with
127.0.0.1. Any check that resolves separately from the connection loses this race. - Connect-time address check
- Hook the HTTP client where it opens the socket (Go
Dialer.Control, OkHttpDns, .NETConnectCallback, Nodelookup, libcurlCURLOPT_OPENSOCKETFUNCTION) or pin the connection to an IP you already checked, so the address you validate is the address you use.
Step-by-Step Attack Flow
A feature fetches a user URL
A link preview, webhook tester, avatar import or HTML-to-PDF renderer passes request data to an HTTP client.
The URL points inward
It names 127.0.0.1, a private host, 169.254.169.254, an encoded IP, a hostname that rebinds, or a public page that redirects inward. The benign test value http://127.0.0.1:8080/health illustrates the case.
The internal service trusts the server
Admin panels, databases with HTTP interfaces, cache servers and the metadata service answer because the request comes from inside the network.
The attacker reads secrets or pivots
Response bodies, status codes or timing leak credentials, configuration and open ports, and stolen cloud keys work from anywhere.
SSRF guides by language
Engineering & System Hardening Checklist
- Run an SSRF rule in CI (Semgrep or CodeQL
request-forgeryqueries, gosec, Brakeman, Psalm TaintedSSRF) and fail on new findings. - Route every outbound fetch of a user URL through one client that checks the connected IP address, not the hostname, and rejects loopback, private, link-local, CGNAT, multicast and IPv4-mapped IPv6.
- Allow only
httpandhttps, disable automatic redirects, and ignore environment proxy variables in that client. - Set connect and total timeouts and cap the response body size.
- Enforce IMDSv2 with a hop limit of 1 on every cloud instance.
- Put a network egress policy or egress proxy in front of fetch workers as a second layer.