Node.js SSRF Guide: Exploits and Prevention

x32x01
  • by x32x01 ||
  • #1
Server-Side Request Forgery, also known as SSRF, is one of the most dangerous web security vulnerabilities developers can accidentally introduce into their applications.
In this article, you'll learn how SSRF works in Node.js, how attackers abuse it, popular bypass techniques, and the right way to secure your code 🔥

What is SSRF in Node.js?​

SSRF (Server-Side Request Forgery) happens when an application accepts a URL from a user and lets the server request it without proper validation.
In simple words: The attacker tricks your server into making requests on their behalf.

Here’s a vulnerable Node.js example:
PHP:
app.get('/fetch', async (req, res) => {
  const { url } = req.query;
  const response = await fetch(url);
  const data = await response.text();
  res.send(data);
});
At first glance, this code looks harmless.
The server receives a URL from the user and fetches its content.
The real problem?
The application blindly trusts user input.
That trust creates an SSRF vulnerability.



How SSRF Attacks Work 🎯​

A regular user might send a request like this:
Code:
GET /fetch?url=https://example.com
Completely normal.
But attackers think differently.
They know the server sends requests from inside your infrastructure.
That means it can access resources that external users normally cannot reach.

Accessing Internal Admin Panels​

An attacker may try:
Code:
GET /fetch?url=http://localhost/admin
The server sends a request to its own internal /admin endpoint.
If the admin dashboard is hidden from public access, the server may still retrieve it and send the response back to the attacker.

Reaching Internal Services​

Attackers can also target internal network services:
Code:
GET /fetch?url=http://192.168.1.105:8080/internal-api
This could expose:
  • Internal APIs
  • Monitoring dashboards
  • Database tools
  • Private microservices
  • Internal management systems
All without direct internet exposure ⚠️



Understanding Blind SSRF 👀​

Sometimes the server performs the request but does not return the response.
This is called Blind SSRF.
You don't see anything useful in the browser.
So how do security researchers confirm the bug?

They use external interaction services like:
  • Burp Collaborator
  • interact.sh
Example payload:
Code:
GET /fetch?url=https://YOUR-ID.burpcollaborator.net

If your collaborator server receives:
  • DNS lookups
  • HTTP requests
  • Connection callbacks
then SSRF exists, even if the application shows no visible output.

Blind SSRF frequently appears inside features such as:
  • Webhooks
  • Link preview generators
  • PDF export systems
  • Import tools
  • Notification services
Any feature where the server fetches user-supplied URLs deserves attention.



A Better SSRF Defense Strategy in Node.js 🛡️​

Many developers try to block dangerous IP strings directly.
That approach is weak.
Attackers rarely send 127.0.0.1 in plain form.
Instead, they may use domains that resolve to internal IP addresses.
A stronger defense starts with DNS resolution validation.

Example:
PHP:
const dns = require('dns').promises;
const ipRangesPrivate = [
  '127.',
  '192.168.',
  '10.',
  '172.16.',
  '169.254.',
  '0.0.0.0'
];

const isPrivateIP = (ip) =>
  ipRangesPrivate.some(range => ip.startsWith(range));
app.get('/fetch', async (req, res) => {
  const { url } = req.query;
  const parsedUrl = new URL(url);
  const { address } =
      await dns.lookup(parsedUrl.hostname);
  if (isPrivateIP(address)) {
    return res.status(403).json({
      message: "Access Denied"
    });
  }

  const safeUrl =
      url.replace(parsedUrl.hostname, address);
  const response = await fetch(safeUrl, {
    headers: {
      Host: parsedUrl.hostname
    }
  });
  res.send(await response.text());
});
This technique helps detect the real IP address before performing the request.
It also reduces the risk of DNS rebinding attacks.



Popular SSRF Bypass Techniques Attackers Use ⚡​

Many SSRF protections fail because attackers know how to bypass weak filters.
Let's explore common tricks.

1. Alternative IP Formats​

Blocking 127.0.0.1 alone is not enough.
Attackers can represent localhost in multiple ways:
Code:
http://127.1/admin
http://2130706433/admin
http://0x7f000001/admin
http://0177.0.0.1/admin
http://[::1]/admin
http://[::ffff:127.0.0.1]/admin
Some libraries interpret these values as the exact same localhost address.

2. Link-Local Address Abuse​

Some developers block private ranges but forget link-local addresses.
Example: http://169.254.169.254/
This address is extremely important in cloud environments.
It often points to cloud metadata services.
In some scenarios, attackers can retrieve temporary cloud credentials from it ☁️

3. NAT64 IPv6 Bypass​

Some filters only block standard NAT64 ranges.
Attackers may abuse alternative prefixes: http://64:ff9b:1::7f00:1/admin
Weak IPv6 validation can allow these requests to bypass security controls.

4. Open Redirect Abuse​

Whitelisting trusted domains is not always enough.
If a trusted site has an Open Redirect vulnerability, attackers can chain requests through it.
Example: GET /fetch?url=https://trusted-site.com/redirect?next=http://169.254.169.254/
Validation approves the trusted hostname.
The server then automatically follows the redirect to the malicious destination.

5. URL Parsing Confusion​

Different parsers sometimes interpret URLs differently.
Attackers abuse parsing edge cases involving:
  • Credentials
  • Special characters
  • Encoding tricks
  • @ symbols
Validation logic may approve one hostname while the actual request goes somewhere else.



The Correct Way to Prevent SSRF in Node.js ✅​

Blacklists alone are not enough.
Attackers constantly discover new bypass methods.
A stronger SSRF defense should include:
✅ DNS resolution validation
✅ Internal IP filtering
✅ Direct IP requests
✅ Redirect blocking
✅ Strict URL validation​

Secure example:
PHP:
const dns = require('dns').promises;
const ipRangesPrivate = [
  '127.',
  '192.168.',
  '10.',
  '172.16.',
  '169.254.',
  '0.0.0.0'
];

const isPrivateIP = (ip) =>
  ipRangesPrivate.some(range =>
      ip.startsWith(range));

app.get('/fetch', async (req, res) => {
  const { url } = req.query;
  const parsedUrl = new URL(url);
  const { address } =
      await dns.lookup(parsedUrl.hostname);
  if (isPrivateIP(address)) {
    return res.status(403).json({
      message: "Access Denied"
    });
  }

  const safeUrl =
      url.replace(parsedUrl.hostname, address);
  const response = await fetch(safeUrl, {
    headers: {
      Host: parsedUrl.hostname
    },
    redirect: 'manual'
  });
  res.send(await response.text());
});

This implementation improves security by:
  • Resolving hostnames before requests
  • Blocking private network access
  • Preventing DNS rebinding
  • Disabling automatic redirects
  • Using safer request handling practices 🔒



Final Thoughts​

SSRF vulnerabilities in Node.js can lead to serious security issues, including:
  • Internal network discovery
  • Hidden admin panel access
  • Cloud credential exposure
  • Infrastructure compromise
The biggest mistake developers make is trusting user-controlled URLs.
If your application fetches external content, SSRF protection should be a core part of your security strategy 🚀
 
Related Threads
x32x01
Replies
0
Views
62
x32x01
x32x01
x32x01
Replies
0
Views
322
x32x01
x32x01
x32x01
Replies
0
Views
691
x32x01
x32x01
x32x01
Replies
0
Views
146
x32x01
x32x01
x32x01
Replies
0
Views
104
x32x01
x32x01
Register & Login Faster
Forgot your password?
Forum Statistics
Threads
944
Messages
951
Members
75
Latest Member
Cripto_Card_Ova
Back
Top