Most SSRF sinks are a library HTTP call: fetch, axios, got, Java HttpClient, Python requests/httpx, Go net/http, Ruby Net::HTTP. These send the request without a JavaScript engine and usually without an interactive session, so the attack surface is the URL, the client's redirect and scheme policy, and whatever headers the code attaches.
The core sink#
The vulnerable shape is a user value flowing into the request target:
const r = await axios.get(req.query.url); // url is attacker-controlled
r = requests.get(user_url, timeout=5)
Pointed at an internal address, the client fetches it and often returns the body or an error that reflects it, giving the attacker a window into the internal network.
Redirect following widens reach#
Library clients differ in how they follow redirects, and that behavior is a bypass surface. A URL on an allowed host that returns Location: http://169.254.169.254/... is followed by a client that validated only the first URL. Whether redirects are followed by default, how many hops are allowed, and whether the scheme may change across a hop all vary by library:
requestsfollows redirects by default;axiosfollows them; Gonet/httpfollows by default with a customizable policy.- Some clients downgrade or refuse a scheme change (for example
httpstofile) on redirect; others do not.
This is the basis of the redirect-based bypass: validate the first hop, connect on a later one.
Scheme handling#
A programmatic client exposes whatever schemes its runtime registers. A Java client built on URL may honor file, ftp, jar, and netdoc; curl-backed clients honor dict, gopher, ftp, tftp, and more. The Scheme subtree depends entirely on what the specific client accepts, so enumerate the registered handlers before committing to a scheme payload.
What it cannot do#
Unlike a headless browser, a programmatic client does not execute returned HTML or script, and it does not carry an interactive session unless the code explicitly attaches credentials. So there is no rendered-script exfiltration, but also no automatic cookie reuse. The payoffs are reading internal responses, scanning via Port timing, and raw-byte interaction through a capable Scheme. Host tricks like DNS rebinding apply because the client re-resolves names.