NPM package with 3 million weekly downloads had a severe vulnerability

NPM package with 3 million weekly downloads had a severe vulnerability
Getty Images

Popular NPM package “pac-resolver” has fixed a severe remote code execution (RCE) flaw.

The pac-resolver package receives over 3 million weekly downloads, extending this vulnerability to Node.js applications relying on the open source dependency. Pac-resolver touts itself as a module that accepts JavaScript proxy configuration files and generates a function for your app to map certain domains to use a proxy.

To proxy or not to proxy

This week, developer Tim Perry disclosed a high-severity flaw in pac-resolver that can enable threat actors on the local network to run arbitrary code within your Node.js process whenever it attempts to make an HTTP request.

While adding proxy support to his HTTP Toolkit, Perry began auditing the pac-resolver code and came across the security issue. Tracked as CVE-2021-23406, the vulnerability has to do with how Proxy Auto-Config (PAC) files are processed by the module. PAC files consist of JavaScript code specifying a proxy configuration—which network requests should go over a proxy and which should go out directly. For example, in a PAC file, network administrators can explicitly specify a network proxy through which all traffic should be routed and show domains that are exempted from the requirement:

function FindProxyForURL(url, host) {
// Send all *.example requests directly with no proxy:
if (dnsDomainIs(host, '.example.com')) {
return 'DIRECT';
} // Send every other request via this proxy:
return 'PROXY proxy.example.com:8080';
}

In the example above, network requests to “example.com” will bypass the proxy, whereas the rest of the traffic is instructed to go through a proxy server.

Originally introduced as part of Netscape Navigator 2.0 in 1996, the PAC standard remains relevant and in widespread use today. For example, Web Proxy Auto-Discovery Protocol (WAPD) uses DNS and/or DHCP services to locate PAC files on a network and import the proxy configuration into an application. However, as proxy configurations become larger, the JavaScript code in a PAC file can get increasingly complex and is ideally designed to run in a virtualized environment (VM).

Few lines of JavaScript can bypass VM, lead to RCE

And that’s where the problem begins.

For example, a related NPM package called Pac-Proxy-Agent, which is made by the same author and has over 2 million weekly downloads, provides PAC file support to Node.js applications. Pac-Proxy-Agent does so by taking in the URL to a PAC file, retrieving the file, and then acting as a Node.js HTTP agent handling outgoing requests for your application. But Pac-Proxy-Agent fails to sandbox PAC files correctly because it uses the vulnerable pac-resolver module, which further relies on “degenerator” to build the PAC function.

Degenerator is yet another package by the same author that helps transform arbitrary code into a sandboxed function using Node.js’ “VM” module. But the VM module was never designed to be used as a security mechanism, something that is explicitly spelled out in Node.js docs. Therefore, the output from degenerator—when used by a chain of packages like pac-resolver, Pac-Proxy-Agent, and proxy-agent—poses a security risk.

Referring to a disclaimer in Node docs saying, “vm module is not a security mechanism. Do not use it to run untrusted code,” Perry said in a blog post, “This is an easy mistake to make—it’s small text (frankly, it should be the headline on that page and next to every method).” Perry further alleges that MongoDB also did “the exact same thing too in 2019, with even worse consequences.” However, the CVE Perrry links to involves a third-party tool named mongo-express. MongoDB confirmed to Ars that they have no affiliation with the package in question.

Perry explained further that “this creates a big problem. While VM does try to create an isolated environment in a separate context, there’s a long list of easy ways to access the original context and break out of the sandbox entirely… allowing code inside the ‘sandbox’ to basically do anything it likes on your system.”

With that, Perry shared a proof-of-concept exploit code demonstrating how an attacker can break out of the VM:

“That’s it—this is all that’s required to break out of the VM module sandbox. If you can make a vulnerable target use this PAC file as their proxy configuration, then you can run arbitrary code on their machine,” he explained.

The vulnerability seriously impacts those who use pac-resolver versions prior to 5.0.0, even transitively in their Node.js application, and:

  • Explicitly use PAC files for proxy configuration or
  • Read and use the operating system proxy configuration in Node.js on systems with WPAD enabled or
  • Use proxy configuration (env vars, config files, remote config endpoints, command-line arguments) from an untrusted source

A remote attacker can, in any of these scenarios, configure a malicious PAC URL and run arbitrary code on a computer any time an HTTP request is made using the proxy configuration.

The fix for pac-resolver in version 5.0.0 consists of simply bumping up the degenerator version to 3.0.1. The core fix went into degenerator itself and implements a stronger sandboxing mechanism via the vm2 module to “prevent privilege escalation of untrusted code.”

Perry thanked Snyk for supporting the developer throughout the coordinated vulnerability disclosure process.

Affected developers should upgrade to pac-resolver version 5.0.0 or above to fix this severe vulnerability in their applications.