Blind SSRF: Exploiting Requests You Cannot See

Blind SSRF: Exploiting Requests You Cannot See

Written by

in

Most write ups about server side request forgery assume you get to read the answer. You send a URL, the server fetches it, and the page or image comes back to you. A blind ssrf is the harder cousin: the server still makes the attacker controlled request, but the response never returns to the attacker. You are firing requests into the dark and have to infer what happened from indirect signals. This post explains how that works, why it stays dangerous even when you cannot see the reply, and how to shut it down. Everything below uses an invented app, so nothing here points at a real target.

If you want the plain version of classic SSRF first, read that, then come back. Here we focus on the case where the body you get back tells you nothing.

What blind ssrf is and how it differs from classic SSRF

Picture an invented app called Acme Notes. It has a webhook feature: you register a URL, and when something changes in your account the server sends a POST to that URL. The server code looks roughly like this.

POST /webhooks
{ "url": "https://hooks.example.com/acme" }

# later, on an event:
# Acme server -> POST {your url}  with a JSON body

In classic SSRF the app hands the fetched response straight back to you on screen. You point the URL at http://localhost:8080/admin and the admin page renders in your browser. You see it. In a blind case the server fires the request but keeps the result to itself. The webhook delivery happens on a background worker. The HTTP status, the body, the headers, all of it stays server side. The app shows you, at most, “delivered” or “failed”.

So the server is still borrowing its trusted position on the network. You just lost your window into the result. That is the whole difference, and it changes how you confirm a finding rather than whether one exists.

Blind does not mean safe. It means the proof moves from the response body to the side channels, and the request still reaches wherever you aimed it.

Why blind ssrf is still dangerous

The damage from SSRF was never really about reading one page. It was about reaching addresses the outside world cannot. A blind version keeps that reach intact.

  • Internal services. Admin panels, message queues, caches, and databases that only listen on private ranges. A POST that triggers an action, like flushing a cache or creating an account, does damage whether or not you read the reply.
  • Cloud metadata. Most cloud providers expose an instance metadata service at a fixed link local address. Even blind, a request aimed there can cause server side effects, and some exfiltration tricks below can pull the data back out of band.
  • State changing requests. Many internal endpoints act on a plain GET or POST. You do not need the response to trip them. You need the request to land.

So the question for a defender is not “can the attacker read the reply”. It is “where is the server willing to send a request, and what happens when it gets there”.

Detecting it with out of band signals

Because the body is gone, you confirm the request another way. Three signals do the work: a callback you control, timing, and error differences.

Out of band callbacks

Stand up a server you own, say probe.attackercontrolled.example, and point the feature at it. If the app reaches out, your listener records the hit. Two layers matter here.

  • DNS. Watch the authoritative DNS server for your domain. A lookup for abc123.probe.attackercontrolled.example proves the server at least resolved your name, even if a firewall blocks the outbound HTTP. DNS often leaks where HTTP cannot.
  • HTTP. If the full request arrives, you also learn the user agent, source address, and any headers the fetcher adds.

A neat trick for the metadata case: some internal endpoints return data that the app then includes in a later outbound request. If you can get a value placed into a hostname your DNS server sees, the blind channel quietly hands you the data. Defenders should assume this is possible and not rely on “the response is hidden”.

Timing

When you cannot get a callback, latency talks. Point the feature at a closed internal port and an open one and compare how long the app takes to answer.

url = http://10.0.0.5:9999/   -> fails fast,  ~5 ms   (connection refused)
url = http://10.0.0.5:6379/   -> hangs then errors, ~2000 ms (something is listening)

A consistent gap maps which internal hosts and ports are alive. It is slow and noisy, but it works when every other channel is closed.

Error differences

The app may say more than it means to. “Invalid response” versus “connection timed out” versus a generic failure are three different states, and each one leaks something about what the server reached. Compare the messages across a public URL, a refused port, and a filtered address. The pattern tells you the request is real.

How to fix it

The fix is the same as for any SSRF, and it does not depend on whether the bug is blind. You decide, on the server, exactly where an outbound request may go. A block list of bad strings loses, because there are too many ways to spell the same address.

  • Allow list outbound destinations. If the webhook only ever needs to reach a few known providers, allow those hosts and refuse the rest. For open ended user webhooks, restrict to public addresses and verify the host before every request.
  • Block link local and internal ranges. Resolve the hostname to an IP first, then reject loopback, private ranges, and the link local metadata address. Do the check after resolving so a name that quietly points inside cannot slip past.
  • Re check on every redirect. A public URL can redirect to an internal one. Validate the destination on each hop, not just the first.
  • Do not accept raw user URLs into a privileged fetcher. Run the part that makes outbound calls with no route to internal systems, so even a landed request reaches nothing useful.
  • Require credentials on metadata. Where your cloud supports a session protected metadata endpoint, turn it on so a bare request returns nothing.

Notice that none of these care about the response body. They constrain the request, which is the only thing a blind attacker still controls.

Closing

Blind ssrf is quiet by nature. The feature works, the screen says “delivered”, and the only thing wrong is where the server agreed to send a request you wrote. Finding it means reading the app for the trust it places in a URL and then proving the request landed through a side channel, not a tidy response. That is exactly the kind of assumption an autonomous researcher that tests how an app is meant to work is built to find. In early testing, a frontier model drove the full methodology on its own and identified and verified real access control and injection issues in test applications it had not seen before. You can read more about UnboundCompute if that approach is interesting.

Frequently asked questions

What is blind ssrf?

Blind ssrf is a server side request forgery flaw where the server makes a request you control but the response never comes back to you. You cannot read the reply, so you confirm and exploit the bug through side signals like a callback to a server you own, timing, or differences in errors.

How is blind ssrf different from classic ssrf?

In classic ssrf the server returns the fetched content, so you see the result directly. In blind ssrf that channel is closed, so you rely on out of band evidence. The server still makes the request, you just have to infer what happened rather than read it.

Is blind ssrf still dangerous if you cannot see the response?

Yes. The server can still be steered to reach internal services and cloud metadata endpoints, which can expose credentials or trigger actions. Out of band confirmation tells the attacker the request landed even when the body is hidden.

How do you detect blind ssrf?

Point suspect inputs at a server you control and watch for DNS or HTTP callbacks that prove the target reached out. Compare response times and error messages between reachable and unreachable destinations, since those gaps reveal the request even when the content is hidden.

How do you prevent blind ssrf?

Do not let users supply raw destinations. Use an allowlist of approved hosts, block link local and internal address ranges, strip redirects, and isolate the egress path so a request cannot reach the metadata service or internal systems.


Put an autonomous researcher on your own systems

UnboundCompute is an autonomous security researcher that reasons about how an application fits together and proves the access control and injection bugs it finds. We are opening a small number of founding design partner seats: private early access pointed at a staging target you choose, a say in what it looks for, and founding pricing. If your team ships software worth pressure testing, apply to the design partner program.