Server-side request forgery (SSRF)

SSRF

SSRF lets an attacker make the application server send requests to destinations the attacker could not normally reach. It can expose internal services, cloud metadata, credentials, and trusted administrative interfaces.

Also known as
Server-side request forgery · Blind SSRF · Cross-service request forgery
Typical severity · Medium to Critical
Last updated
On this page: What it is
  1. 1 · What it is
  2. 2 · Why it matters
  3. 3 · Examples
  4. 4 · How to fix it
  5. 5 · How to test for it
  6. References

What it is#

Server-side request forgery occurs when an application fetches a URL, opens a connection, or resolves a network location influenced by untrusted input. The attacker is not connecting to the destination directly; the vulnerable server makes the request on their behalf.

Common entry points include URL previews, webhook testers, document converters, image importers, feed readers, proxy endpoints, PDF generators, and integrations that accept callback URLs.

  • Direct SSRF returns the downstream response to the user.
  • Blind SSRF sends the request but does not return its body. DNS records, timing, errors, or a controlled callback can still prove that the request occurred.
  • Second-order SSRF stores a URL first and retrieves it later from a background worker.
  • Protocol abuse occurs when a fetcher accepts schemes other than the intended https or http protocols.

The security boundary is the server's network position. A destination that is unreachable from the internet may still trust requests from the application network.

Why it matters#

  • Reach internal dashboards, databases, service-discovery endpoints, or administrative APIs.
  • Query cloud instance-metadata services and expose short-lived credentials.
  • Bypass IP allowlists because the request originates from a trusted application server.
  • Scan internal hosts by comparing response codes, errors, or timing.
  • Read data from unintended protocols or local resources when the URL library supports them.
  • Trigger state-changing requests against internal services that do not expect hostile input.
Typical severity

Medium when requests are tightly constrained and expose little information. High to critical when the server can reach cloud metadata, management services, credentials, or sensitive internal networks. Actual severity depends on context: who is affected, what data or actions are reachable, and existing controls.

Examples#

✕ Vulnerablejavascript
// Vulnerable: the user controls the complete destination.
app.post('/api/preview', requireLogin, async (req, res) => {
  const response = await fetch(req.body.url);
  res.type('text/plain').send(await response.text());
});
✓ Fixedjavascript
// Fixed: choose destinations by server-owned identifier.
const feeds = new Map([
  ['status', 'https://status.example.com/feed.json'],
  ['news', 'https://news.example.com/feed.json'],
]);

app.post('/api/preview', requireLogin, async (req, res) => {
  const destination = feeds.get(req.body.feedId);
  if (!destination) return res.status(400).json({ error: 'Unknown feed' });

  const response = await fetch(destination, {
    redirect: 'error',
    signal: AbortSignal.timeout(5000),
  });
  res.type('application/json').send(await response.text());
});

If a business requirement genuinely needs arbitrary customer domains, validate the parsed URL rather than searching the raw string:

Examplejavascript
const parsed = new URL(candidate);
if (parsed.protocol !== 'https:') throw new Error('HTTPS is required');
if (parsed.username || parsed.password) throw new Error('Userinfo is not allowed');

That syntax check is only one layer. DNS and network controls are still required.

How to fix it#

1. Avoid arbitrary URLs. Accept an opaque destination ID and map it to a server-owned URL. This is safer than trying to recognize every dangerous URL form.

2. Allowlist exact destinations. When customers must configure integrations, store approved scheme, hostname, and port separately. Compare normalized values exactly. Do not use substring or suffix checks that can be fooled by lookalike domains.

3. Restrict resolution and routing. Resolve the hostname, reject loopback, link-local, private, multicast, reserved, and internal address ranges, and repeat the check after every DNS resolution. Protect against IPv4, IPv6, alternative numeric formats, and DNS rebinding.

4. Disable redirects or validate every redirect hop. A public URL can redirect to a private destination. Set strict timeouts and response-size limits.

5. Enforce outbound network policy. Application workloads should only reach required destinations through an egress proxy or firewall. Block cloud metadata endpoints and management networks at the network layer. Use the cloud provider's hardened metadata mode where available.

6. Limit protocols and parser behavior. Permit only required schemes, normally https. Disable URL handlers for local files and non-HTTP protocols.

7. Separate fetchers from sensitive networks. Run high-risk preview or conversion workers in an isolated network with no access to administrative services or workload credentials.

8. Log decisions safely. Record the normalized destination, resolved address, redirect result, requesting user, and policy decision without storing credentials embedded in URLs.

How to test for it#

  • Inventory features that accept URLs, hostnames, webhooks, import locations, image links, or remote documents, including asynchronous workers.
  • Use a controlled HTTPS endpoint that records a unique, harmless request token. Confirm whether the application server makes the request.
  • Verify that loopback, private, link-local, reserved, and IPv6-local destinations are rejected before a connection is attempted.
  • Test an approved public URL that redirects to a blocked test address. The redirect must be rejected.
  • Test alternate URL representations: mixed case, trailing dots, encoded separators, userinfo, scheme-relative URLs, and hostnames that resolve to multiple addresses.
  • Confirm that only required protocols and ports are accepted and that response size and timeout limits are enforced.
  • Perform cloud-metadata checks only in an isolated test account using a harmless fixture that cannot return credentials.
  • Review egress firewall or proxy logs to confirm that application workloads cannot bypass the destination policy.

References#

Permalinklibrary.infinity8labs.com/server-side-request-forgery/JSON
Found this in Breachvane? Your finding links here for background. Evidence, affected assets and retest status are in your Breachvane ↗ (opens in a new tab) workspace. Need help fixing it? Talk to us.