~ 3 min read
Bypassing SSRF Safeguards in ssrfcheck: A Case of Incomplete Denylists

Attention security professionals, another SSRF bypass for us. Today I’ll examine a vulnerability within ssrfcheck
, a popular npm package designed to shield applications from SSRF (Server-Side Request Forgery) attacks. While ssrfcheck
employs a denylist to identify unsafe URLs, a critical omission renders its protection incomplete (yikes!). Let’s dissect the issue and explore its technical implications.
Understanding ssrfcheck: Your (Mostly) Trusted SSRF Ally
SSRF vulnerabilities emerge when an application unwittingly makes requests to external servers based on user-controlled input. Attackers can exploit this to fetch internal resources, execute unauthorized actions, or even launch denial-of-service attacks.
ssrfcheck
steps in by offering a validation layer. It maintains a denylist of IP addresses and ranges considered unsafe for outbound requests. If a provided URL resolves to an IP address on this list, the request is likely an SSRF attempt and gets flagged.
However, a closer look reveals a gap in ssrfcheck
’s defense mechanism.
The Vulnerability: A Blind Spot in the Denylist
The crux of the issue lies in the way ssrfcheck
constructs its denylist. While it includes various unsafe IP ranges, it overlooks a crucial category: reserved IP address spaces as defined by the IANA (Internet Assigned Numbers Authority).
Specifically, the denylist lacks the following reserved range:
224.0.0.0/4: This denotes the multicast address space, typically used for one-to-many communication on network protocols like UDP.
In real-world scenarios, exploiting this specific address space for SSRF attacks might be less common. However, the principle remains: a well-designed SSRF protection package should adhere to established standards for identifying invalid public IP addresses.
For context, other popular npm packages like ipaddr.js
(often used in conjunction with SSRF protection) correctly classify the aforementioned range as reserved and not a valid public IP address.
👋 Just a quick break
I'm Liran Tal and I'm the author of the newest series of expert Node.js Secure Coding books. Check it out and level up your JavaScript
Analyzing the Technical Landscape: Proof of Concept (PoC)
To solidify our understanding, let’s delve into a code example demonstrating the bypass:
- Install the
ssrfcheck
package:
npm install ssrfcheck
- Define an
app.js
file with the programmatic API ofssrfcheck
:
import { isSSRFSafeURL } from 'ssrfcheck';
let resultresult = isSSRFSafeURL('https://012.1.2.3/whatever');console.log(result); // returns falseresult = isSSRFSafeURL('https://localhost:8080/whatever');console.log(result); // returns false
result = isSSRFSafeURL('https://239.255.255.250:8080/whatever');console.log(result); // returns true - bypassed
As you can observe, ssrfcheck
incorrectly allows the URL with the reserved multicast IP address (239.255.255.250
), potentially opening a vulnerability window.
Coordinated Security Disclosure and Next Steps
This vulnerability highlights the importance of comprehensive denylists in SSRF protection tools. Here’s what you can do:
- Upgrade
ssrfcheck
: Once a patched version is released, update your packages to benefit from the fixed denylist. - Consider alternatives: Explore other SSRF protection libraries that offer more robust and up-to-date denylists.
- Defense in depth: Remember, SSRF protection is a multi-layered approach. Combine validation tools with input sanitization and framework-specific security measures for optimal defense.
Hack away responsibly!