Published blocklist
What the relay refuses, in full.
A guard is only worth what it will not do. This page is the complete list of what Backfire will not dial, will not follow and will not accept — kept in step with the code that enforces it, so you can check the promise instead of believing it.
Try it
This is a real request against the live relay. It asks for the instance metadata service — the target behind most SSRF incidents — and gets refused before a socket opens.
curl -s https://backfireapi.base44.app/functions/forward \
-H "Authorization: Bearer backfire_…_api" \
-H "Content-Type: application/json" \
-d '{"url":"http://169.254.169.254/latest/meta-data/","method":"GET"}'What comes back
A 403 with a machine-readable code and the reason, written into your activity log. The attempt is recorded; your balance is not touched.
{
"ok": false,
"request_id": "8f1c4b7a…",
"error": {
"code": "blocked_target",
"message": "169.254.169.254 resolves to a private,
loopback, link-local or metadata address."
}
}IPv4
Sixteen ranges are never dialled.
Checked against every address a hostname resolves to, not just the hostname string. A name that is both public and private resolves to a refusal.
| ipv4 range | why it is refused |
|---|---|
| 0.0.0.0/8 | This network — never a real destination |
| 10.0.0.0/8 | Private range |
| 100.64.0.0/10 | Carrier-grade NAT |
| 127.0.0.0/8 | Loopback |
| 169.254.0.0/16 | Link-local — where cloud metadata lives |
| 172.16.0.0/12 | Private range |
| 192.0.0.0/24 | IETF protocol assignments |
| 192.0.2.0/24 | Documentation range |
| 192.88.99.0/24 | 6to4 relay anycast |
| 192.168.0.0/16 | Private range |
| 198.18.0.0/15 | Benchmarking range |
| 198.51.100.0/24 | Documentation range |
| 203.0.113.0/24 | Documentation range |
| 224.0.0.0/4 | Multicast |
| 240.0.0.0/4 | Reserved |
| 255.255.255.255/32 | Broadcast |
IPv6
The same rules, written for the other stack.
| ipv6 rule | why it is refused |
|---|---|
| :: | Unspecified address |
| ::1 | Loopback |
| fc00::/7 | Unique local |
| fe80::/10 | Link-local |
| fec0::/10 | Site-local |
| ff00::/8 | Multicast |
| 2001:db8::/32 | Documentation range |
| 2002::/16 | 6to4 |
| 64:ff9b::/96 | NAT64 — unwrapped and checked as IPv4 |
| ::ffff:0:0/96 | IPv4-mapped — checked as IPv4 |
Hostnames
- localhost
- metadata
- metadata.google.internal
- instance-data
- metadata.azure.internal
Plus any name ending in .localhost, .local, .internal, .localdomain, .home.arpa.
Ports
- 25SMTP
- 465SMTPS
- 587Submission
Mail ports are refused so the relay cannot be turned into a spam path.
Structural refusals
And the eight things a request cannot do.
Redirects are never followed
A 3xx comes back to you with its Location header and nothing else. The classic SSRF bypass — a public URL that answers 302 to 169.254.169.254 — never gets a second request from us.
Only http and https, with no credentials in the URL
file:, ftp:, gopher: and data: are refused. A URL carrying user:pass@ is refused too, because the relay is not a place to smuggle a credential past a log.
WebSocket targets need their own endpoint
A ws:// or wss:// target is refused at the forward endpoint and has to be opened through the socket route, where it gets its own ticket, expiry and frame counters.
8 MB in, 8 MB out
A request body above 8 MB is refused before the call. A response is read up to 8 MB and then stopped, so one oversized upstream cannot become a memory event on your bill or ours.
30 seconds, clamped
You may ask for any timeout up to 30 seconds; above that it is clamped, and below 1 second it is raised. The upstream cannot hold the relay open indefinitely.
Header hygiene, enforced
At most 32 headers, 1024 characters each, no CR or LF anywhere, hop-by-hop headers stripped. Authorization, cookie, key and token values are redacted in the log line we keep.
600 forwards a minute per key
Plus 1,200 a minute per account. Past the ceiling a request cools down for 10 seconds and is refused rather than queued — and a refusal is never charged.
DNS that fails, fails closed
No answer, a broken resolver, or an answer we cannot classify is a refusal. There is no fallback path that guesses what you meant.
What this does not do
It narrows the SSRF gap. It does not make it zero.
The relay checks the addresses a name resolves to, then makes the call — which resolves the name again. A hostname that answers publicly at check time and privately a moment later is a race this design narrows but does not eliminate. The write-up is public.
It also cannot tell you whether you were allowed to call a target in the first place, cannot pin a customer's allowlist to an address, and cannot reach a service that only accepts connections from inside your own network. Those are different products, and pretending otherwise is how security pages lose their readers.
Every refusal above has an error page with the exact retry semantics.
All error codes