Finding SSRF in the Wild
URL params, webhook URLs, file imports, document preview, SSO SAML assertions — every place the server fetches a URI the attacker controls.
URL params, webhook URLs, file imports, document preview, SSO SAML assertions — every place the server fetches a URI the attacker controls.
SSRF vulnerabilities hide in plain sight. Any feature that takes a URL, a hostname, or a file path from the user and uses it to make a server-side request is a potential SSRF vector. Learning to recognise these patterns is the first step to finding SSRF in the wild.
SSRF entry points fall into several categories. The most obvious is a URL parameter like ?url=, ?file=, ?next=, or ?redirect=. These are easy to spot in a URL. But SSRF also hides in features that are not obviously URL-based: webhook configuration panels, file import tools that fetch remote resources, document preview features that render external pages, and avatar uploaders that fetch from a user-provided URL.
PDF generators are a notable SSRF hotspot. Many applications offer the ability to generate a PDF from a URL — you paste a link, the server renders the page as a PDF, and you download the result. The server must fetch the URL to render it, and if the URL is not validated, the server can be pointed at internal services. The generated PDF then becomes an exfiltration channel: the contents of the internal page appear in the PDF that the attacker downloads.
SSO endpoints are more subtle. In SAML-based SSO, the service provider receives an assertion from the identity provider and may fetch the Assertion URL embedded in the SAML response. An attacker who controls the identity provider — or who finds a SAML injection bug — can embed an internal URL in the assertion and trigger a server-side fetch. Similar patterns exist in OAuth state parameters and OpenID Connect request URIs.
The tool below presents six endpoints commonly found in web applications. Click each one to probe it for SSRF — the panel shows whether the server makes a request to your controlled URL. A vulnerable endpoint fetches the URL without validation; a safe one blocks it.
Click each endpoint to probe it for SSRF. The scanner sends an internal URL and checks if the server fetches it.
Click an endpoint to probe for SSRF.
In 2019, a security researcher discovered an SSRF vulnerability in a widely used PDF generation service. The service accepted a URL parameter and rendered the page as a PDF. By passing an internal URL like http://localhost:8080/admin, the attacker could generate a PDF of any internal dashboard or admin panel. The response was returned as a downloadable PDF — a perfect out-of-band SSRF channel. The vulnerability was particularly dangerous because the PDF generator ran in the internal network with access to databases, caches, and orchestration tools.
This case illustrates why URL-based features are so frequently vulnerable. Developers building PDF generators, screenshot services, or link previewers focus on the rendering output and often forget that the input URL is an attack surface. The fix was an allowlist of permitted domains and a block on private IP ranges after DNS resolution.
The first step is inventory: audit every feature that makes a server-side HTTP request based on user input. Look for URL parameters, configuration fields that accept URLs, file import features, SAML assertion processing, and any code that calls fetch() or curl with user-controlled input.
// VULNERABLE - webhook endpoint without validation
app.post('/api/webhooks', (req, res) => {
const { url } = req.body;
await fetch(url); // any URL, any destination
});
// SAFE - validate protocol, host, and path
const SAFE_PROTOCOLS = ['https:'];
const BLOCKED_IPS = ['127.0.0.0/8', '10.0.0.0/8',
'172.16.0.0/12', '192.168.0.0/16', '169.254.0.0/16'];
function validateUrl(input) {
const url = new URL(input);
if (!SAFE_PROTOCOLS.includes(url.protocol)) throw Error();
const ip = dnsResolveSync(url.hostname);
if (isPrivateIp(ip, BLOCKED_IPS)) throw Error();
return url;
}
app.post('/api/webhooks', (req, res) => {
const url = validateUrl(req.body.url);
await fetch(url);
});Use automated scanning tools to test all endpoints with internal URLs and monitor for unexpected DNS lookups or connections. Pay special attention to POST endpoints that accept JSON — SSRF entry points are often hidden in API request bodies rather than query parameters.
1.Which of the following is LEAST likely to be an SSRF entry point?
2.Why are PDF generators a particularly dangerous SSRF vector?
3.What is the minimum validation every URL-fetching feature should implement?