~ 3 min read

SSRF Vulnerability in safe-axios: Unintended Public Address Classification

share on
This write-up explores a critical vulnerability within `safe-axios`, an npm package aimed at safeguarding applications from SSRF (Server-Side Request Forgery) attacks.  While `safe-axios` attempts to validate URLs through a provided function, a fundamental design flaw opens the door for potential exploitation. We'll review the technical details, analyze the exploit, and highlight the importance of secure coding practices.

This write-up explores a critical vulnerability within safe-axios, an npm package aimed at safeguarding applications from SSRF (Server-Side Request Forgery) attacks. While safe-axios attempts to validate URLs through a provided function, a fundamental design flaw opens the door for potential exploitation. We’ll review the technical details, analyze the exploit, and highlight the importance of secure coding practices.

Understanding safe-axios: Intended SSRF Functionality and Shortcomings

SSRF vulnerabilities arise when an application unwittingly makes requests to external servers based on user-controlled input. Attackers can leverage this to steal sensitive data, execute unauthorized actions, or disrupt operations.

The safe-axios library seeks to mitigate this risk by offering a validation layer. It exports a function called isPrivateAddress intended to determine if an IP address falls within a private range. If the input resolves to a private IP, it’s considered safe for internal communication.

However, a closer look reveals a significant shortcoming in isPrivateAddress’s implementation.

The Vulnerability: A Function Misnamed and Misused

The crux of the issue lies in the very definition of isPrivateAddress. Here’s the relevant code snippet from safe-axios:

export function isPrivateAddress(ip: string): boolean {
const range = CIDRList.find(r => {
return ipRangeCheck(ip, r);
});
if (range) {
return true;
}
return false;
}

Let’s break down the problem:

  • Function Misnomer: Despite its name, isPrivateAddress doesn’t actually validate the input as an IP address. It accepts any string, including URLs or even empty strings.
  • Incorrect Validation Logic: Even if it were limited to IP addresses, the function focuses solely on private ranges. It doesn’t distinguish between valid public IPs and other invalid inputs.

As a consequence, malicious actors can exploit this vulnerability by providing URLs or arbitrary strings. Since these won’t match the private IP ranges, isPrivateAddress incorrectly classifies them as public addresses, potentially allowing for outbound SSRF attacks.

đź‘‹ 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

Node.js Secure Coding: Defending Against Command Injection Vulnerabilities
Node.js Secure Coding: Prevention and Exploitation of Path Traversal Vulnerabilities

Practical SSRF Bypass Demonstration

To illustrate the exploit, let’s create a basic example:

  1. Install the safe-axios package:
Terminal window
npm install safe-axios
  1. Define an app.js file with the programmatic API of safe-axios:
import { isPrivateAddress } from 'safe-axios';
let result
result = isPrivateAddress('127.0.0.1');
// expected: true
// actual: true
console.log(result);
result = isPrivateAddress('localhost');
// expected: true
// actual: false
console.log(result);
result = isPrivateAddress('https://localhost:3000/asdadsa');
// expected: true
// actual: false
console.log(result);
result = isPrivateAddress('192.32.196.4');
// expected: true
// actual: false
console.log(result);
result = isPrivateAddress('');
// expected: true
// actual: false
console.log(result);

As you can see, isPrivateAddress fails to identify various non-private IP addresses and even allows a public URL through.

The Importance of Secure Coding Practices

This vulnerability highlights the critical role of secure coding practices in preventing vulnerabilities like SSRF. Here are some key takeaways:

  • Input Validation: Always validate user-provided input to ensure it conforms to the expected format and data type. In this case, isPrivateAddress should only accept valid IP addresses.
  • Function Naming: Choose clear and descriptive function names that accurately reflect their purpose. This helps developers understand the intended usage and avoid potential misuse.
  • Least Privilege: Implement the principle of least privilege. Functions like isPrivateAddress should operate with the minimal level of access necessary.

These principles form the foundation of secure coding, as outlined in my book series, Node.js Secure Coding. By adhering to these guidelines, developers can significantly reduce the likelihood of introducing vulnerabilities in their code.


Node.js Security Newsletter

Subscribe to get everything in and around the Node.js security ecosystem, direct to your inbox.

    JavaScript & web security insights, latest security vulnerabilities, hands-on secure code insights, npm ecosystem incidents, Node.js runtime feature updates, Bun and Deno runtime updates, secure coding best practices, malware, malicious packages, and more.