SSRF: The Complete Practical Guide to Server-Side Request Forgery
Basic SSRF: Reaching Internal URLs
How in-band SSRF works: finding the URL parameter, swapping the host for 127.0.0.1, reaching endpoints the front end hides, and reading the reflected response.
Published
Basic SSRF is the in-band case: you give the app a URL, it fetches that URL from the server, and it shows you the response. Because the request comes from the server, you can point it at things the firewall would never let you reach directly, and read the answer right there in the app. It is the cleanest place to build the SSRF reflex.
What an in-band SSRF looks like
An app has a feature that takes a URL and fetches it: a link preview, an "import from URL," a webhook tester, a PDF-from-URL generator. The response, or part of it, comes back to you. The giveaway is that the content you see is clearly fetched server-side, not loaded by your own browser.
POST /api/preview
{ "url": "https://example.com/page" } -> returns the fetched page's title and bodyIf you control that url and the server fetches whatever you put there, you have the primitive.
Finding the URL parameter
The obvious inputs are named url, uri, link, src, dest, feed, callback, or webhook. The less obvious ones hide in places people forget to check:
- Nested fields in a JSON body.
- Headers the app acts on, like a custom
X-Forwarded-Hostor a webhook target. - Indirect inputs, where you supply a document (XML, SVG, an Office file) that itself references a URL the parser follows.
Test every value that could become a destination, not just the one labelled url.
Confirming the server fetches it
Before aiming at anything internal, prove the fetch happens. Point the input at a server you control and watch your logs:
url = http://your-listener.example/probeAn inbound hit from the application's IP (not your own) confirms two things: the server makes the request, and it makes it to an attacker-chosen host. Now you can redirect it somewhere useful.
Swapping the host for 127.0.0.1
The first interesting target is the server talking to itself. Loopback is only reachable from on-box, so a response here means you are inside:
http://127.0.0.1/
http://127.0.0.1:8080/
http://localhost/Many internal services bind to loopback precisely because they assume only the host can reach them. SSRF breaks that assumption.
Reaching an admin endpoint the front end hides
Front ends often hide privileged routes behind the proxy, trusting that only internal traffic reaches them. From the server, you can request them directly:
http://127.0.0.1/admin
http://127.0.0.1:8080/actuator/env (Spring Boot internals)
http://127.0.0.1:9200/_cat/indices (Elasticsearch)If the app renders the fetched body, you read internal dashboards, config, and health endpoints that were never meant to face you.
Reading the reflected response
The value of in-band SSRF is the response. Look at exactly what comes back:
- The full body (you read the internal page directly).
- Just a title, a length, or a snippet (enough to confirm and often enough to extract).
- An error that still leaks information (a connection refused versus a timeout tells you whether a port is open).
Read whatever the app gives you, and shape your next request from it.
When it only half-works
SSRF is often partial, and the partial signals are useful:
- Status codes. A
200versus a500versus a403tells you whether the internal target exists and responded. - Timing. A fast refusal means a closed port, a hang until timeout means a filtered one, and a quick body means it is open.
- Redirects. Some fetchers follow redirects, which lets you pass a filter with an allowed host that then redirects internally (covered in allow-list and filter bypass).
- Scheme and header limits. A plain URL fetcher often cannot set custom headers, which matters for targets that require them.
When the body never comes back at all, you are in blind SSRF territory and switch to out-of-band detection.
Basic in-band SSRF is where the mental model clicks: your URL, the server's network. Try it on a free live target, then move to blind SSRF for when the response disappears.
← Back to SSRF: The Complete Practical Guide to Server-Side Request Forgery