ROOTVIELROOTVIEL
← Knowledge Base

Application & code

Educational12 min

Server-Side Request Forgery (SSRF)

An application makes an outbound request to a URL it takes from untrusted input, so the attacker aims the server’s own network position at internal services, cloud metadata, or arbitrary hosts — reaching resources a direct external request never could.

Classification

Domain
Application & code
ROOTVIEL support
Educational — Recognized concept, documented for learning — not detected by ROOTVIEL.
Analysis family
code-src
CWE
CWE-918
OWASP
A10:2021-Server-Side Request Forgery (SSRF)

Definition

Server-Side Request Forgery is the failure to constrain the destination of a request the server makes on a user’s behalf. The application accepts a URL (or a host, or a value that becomes part of a URL) from untrusted input and fetches it — to retrieve a webhook target, render a remote image, import a document, check a link, or call a dependency. Because the fetch originates from the server, it inherits the server’s network position: it can reach internal addresses, cloud metadata endpoints, and services behind the perimeter that an external attacker cannot touch directly.

The core of SSRF is the mismatch between who chooses the destination (the attacker) and whose trust the request carries (the server). The attacker does not need to see the response in every case — blind SSRF against an internal service, or against a metadata endpoint that returns credentials, can be devastating even when nothing is reflected.

Context

SSRF appears in any feature where the server fetches a user-influenced URL: webhooks and callback registration, URL preview/unfurling, importing from a link, server-side PDF/HTML/image rendering, document conversion that fetches remote resources, file upload "from URL", and integrations that take an endpoint address from configuration the user controls. It also arises indirectly through XXE (http:// entities) and through libraries that follow redirects or parse URLs loosely.

  • ▸Webhook/callback features that POST to a user-supplied URL.
  • ▸Link preview, image proxy, and "import from URL" functions.
  • ▸Server-side rendering/conversion that fetches remote stylesheets, images, or includes.
  • ▸Integrations where the user configures a remote endpoint the server then calls.
  • ▸Cloud environments where an internal metadata service exposes credentials to any local request.

Technical fundamentals

An outbound HTTP client resolves a hostname to an address and connects. SSRF defence is about controlling the address that is actually connected to, which is harder than it looks because of three moving parts: name resolution (a hostname can resolve to an internal IP, and DNS answers can change between the check and the connect — a rebinding race), redirects (a safe-looking URL can 302 to an internal one), and URL parsing quirks (alternate encodings, credentials in the authority, uncommon schemes). A string check on the submitted URL is therefore insufficient.

The clean model is taint dataflow with the outbound-request call as the sink, combined with an egress policy enforced at connect time. The robust design is an allow-list of permitted destinations validated against the resolved IP, not the hostname string, with redirects disabled or re-validated and the request forced through a controlled egress path that blocks private and link-local ranges. Blocklists of "internal" strings are fragile; the connection is what must be governed.

Egress allow-list
A fixed set of destinations the server may call, enforced on the resolved IP at connect time, not on the input string.
DNS rebinding
A race where a hostname passes a check but resolves to an internal IP at connect time, defeating pre-resolution validation.
Metadata endpoint
A link-local address in many cloud environments that returns instance credentials to any local request — a prime SSRF target.
Blind SSRF
The response is not returned to the attacker, but the request itself (to an internal service or metadata) causes the damage.

Root cause

The root cause is letting untrusted input decide the destination of a server-originated request without constraining where that request may actually go. The developer validates the URL as a string (or not at all) and trusts the HTTP client to "just fetch it", not accounting for the server’s privileged network position or for resolution and redirect behaviour. The fix is to govern the connection: allow-list destinations by resolved IP, block internal ranges at the network layer, and control redirects.

A reinforcing cause is the cloud metadata service: a single unconstrained fetch can retrieve instance credentials because the metadata endpoint trusts any local request. This is why SSRF rose to its own Top 10 category — the blast radius in cloud environments is large and the exploit is simple.

How the attack works, step by step

  1. 1A feature fetches a user-supplied URL — say, a webhook test or an image preview.
  2. 2The attacker supplies a URL pointing at an internal address, a cloud metadata endpoint, or another service behind the perimeter.
  3. 3The server resolves and connects from its own network position, reaching a destination the attacker could not reach directly.
  4. 4The server returns the response (in-band) or simply performs the request (blind) — retrieving metadata credentials, hitting an internal admin API, or probing internal hosts and ports.
  5. 5Because the destination was attacker-chosen but the request carried the server’s trust, the perimeter provided no protection.

Common escalations: read cloud instance credentials from the metadata endpoint and reuse them; port-scan the internal network by observing response timing and errors; and bypass naive filters with redirects, DNS rebinding, alternate IP encodings, or credentials-in-URL tricks.

Vulnerable example

A synthetic, illustrative link-preview endpoint that fetches whatever URL the client provides, with no destination control:

synthetic — do not use; illustrates the flaw
// UNSAFE: the server fetches an attacker-chosen destination. async function preview(req, res) { const url = req.query.url // No destination control: resolves and connects from the server's position, // and follows redirects by default. const resp = await fetch(url) res.send(await resp.text()) } // Attacker sends url pointing at an internal metadata endpoint, e.g. // http://169.254.169.254/latest/meta-data/iam/security-credentials/ // The server fetches it and returns instance credentials to the attacker.

Corrected example

The fix governs the connection: parse and allow-list the destination, resolve the hostname and reject private/link-local IPs, pin the connection to the validated IP, and disable (or re-validate) redirects. An allow-list of exact hosts is stronger still where the set of destinations is known.

synthetic — validate the resolved IP, pin it, no redirects
const dns = require("node:dns/promises") const net = require("node:net") const ALLOWED_HOSTS = new Set(["images.example-cdn.test"]) // when destinations are known function isPrivate(ip) { // reject loopback, private, link-local (incl. metadata 169.254.0.0/16), etc. return /^(127\.|10\.|192\.168\.|169\.254\.|::1|fc|fd)/i.test(ip) || (ip.startsWith("172.") && (+ip.split(".")[1] >= 16 && +ip.split(".")[1] <= 31)) } async function preview(req, res) { let u try { u = new URL(req.query.url) } catch { return res.status(400).end() } if (u.protocol !== "https:") return res.status(400).end() // scheme allow-list if (!ALLOWED_HOSTS.has(u.hostname)) return res.status(403).end() // host allow-list // Resolve and validate the ACTUAL IP; pin the connection to it to avoid // DNS rebinding between check and connect. const { address } = await dns.lookup(u.hostname) if (isPrivate(address)) return res.status(403).end() const resp = await fetch(u.href, { redirect: "error", // do not auto-follow to a new destination // connect pinned to 'address' via a custom agent/lookup in real code }) res.send(await resp.text()) }
Note

Limit of the fix: validating the hostname string is not enough — you must validate the resolved IP and pin the connection to it, or a DNS-rebinding race re-points the hostname to an internal address after the check. Redirects must be disabled or re-validated against the same policy at every hop. The private-range check shown is illustrative and incomplete; enforce egress rules at the network layer (a locked-down egress proxy / security group) as the authoritative control, with application checks as defence in depth. Disabling access to the metadata endpoint (or requiring its hardened mode) closes the highest-value target.

Impact

  • ▸Cloud credential theft: read instance credentials from a metadata endpoint and assume the server’s role.
  • ▸Internal access: reach admin APIs, databases, and services that the perimeter was supposed to protect.
  • ▸Reconnaissance: port-scan and fingerprint internal hosts via timing and error differences (blind SSRF).
  • ▸Pivot and chaining: combine SSRF with weak internal auth to move laterally, or use it to exfiltrate data out-of-band.

Detection

The structural signal is a taint path from untrusted input to an outbound-request sink (HTTP client, URL fetch, library that dereferences a URL) with no destination control between them. Static analysis flags these but cannot evaluate runtime resolution or redirects. Dynamic testing is decisive: point the feature at an attacker-controlled server and observe an out-of-band callback (confirming the server fetches arbitrary destinations), then test internal and metadata addresses, redirect chains, DNS rebinding, and alternate IP encodings. An observed request to a controlled or internal host is strong evidence.

Where ROOTVIEL fits

This entry is reference material. ROOTVIEL’s verified, execute-and-prove engine is focused on the AI/agentic and Web3 domains, where it confirms a finding by running the attack in a sandbox against a deterministic check. SSRF is an application/code weakness whose exploitability depends on the deployment’s network and cloud environment; ROOTVIEL does not currently settle it with a verified engine, so a finding here is educational unless it is independently demonstrated in that environment.

Note

Support: educational. The input → outbound-request dataflow is detectable, but exploitability is environment-specific (what internal services and metadata exist). ROOTVIEL does not promote a verified SSRF finding; treat a match as a hypothesis to confirm with an out-of-band probe.

Mitigation

Govern the connection, not just the input string; enforce egress at the network layer and allow-list destinations in code.

  • ▸Preventive: maintain an allow-list of permitted destinations and schemes; validate against the resolved IP, and pin the connection to that IP to defeat DNS rebinding.
  • ▸Preventive: block private, loopback, and link-local ranges (including the cloud metadata address) at the network layer via a locked-down egress proxy or security groups.
  • ▸Preventive: disable automatic redirect following, or re-validate each redirect hop against the same policy.
  • ▸Preventive: harden or disable the cloud metadata endpoint (require its hardened/token mode) so a single fetch cannot leak credentials.
  • ▸Detective: run static taint analysis for input→outbound-request paths and review URL-fetching features.

Verifying the mitigation

Verify by confirming every URL-fetching path validates the resolved IP (not just the hostname), pins the connection, disallows redirects to new destinations, and is subject to network-layer egress controls. Then attempt exploitation: target the metadata address, internal hosts, redirect chains, rebinding, and alternate encodings, and confirm each is refused or cannot reach an internal destination. Report as "these attempts failed in the tested environment", acknowledging that the result is tied to the current network topology.

Note

A clean result is environment-specific: the same code in a different network may be exploitable. Keep egress controls authoritative at the network layer, since application-level checks alone are prone to resolution and redirect bypasses.

Common mistakes

  • ▸Validating the hostname string but connecting after a fresh resolution, leaving a DNS-rebinding race.
  • ▸Blocklisting "localhost"/"127.0.0.1" while missing alternate encodings, IPv6, and the metadata link-local address.
  • ▸Allowing automatic redirect following, so a safe URL 302s to an internal one.
  • ▸Relying only on application checks with no network-layer egress control.
  • ▸Assuming blind SSRF is low-risk because no response is reflected, ignoring metadata credential theft.

References

  1. [1]MITRE CWE-918 (Server-Side Request Forgery)
  2. [2]OWASP Top 10 — A10:2021 Server-Side Request Forgery
  3. [3]OWASP Cheat Sheet — Server-Side Request Forgery Prevention
  4. [4]PortSwigger Web Security Academy — SSRF

References point to public, well-known technical sources for further study.

Related articles