Skip to content
PhantomRaven

NPM flooded with malicious packages downloaded more than 86,000 times

Packages downloaded from NPM can fetch dependencies from untrusted sites.

Dan Goodin | 64
Credit: Getty Images
Credit: Getty Images
Story text

Attackers are exploiting a major weakness that has allowed them access to the NPM code repository with more than 100 credential-stealing packages since August, mostly without detection.

The finding, laid out Wednesday by security firm Koi, brings attention to an NPM practice that allows installed packages to automatically pull down and run unvetted packages from untrusted domains. Koi said a campaign it tracks as PhantomRaven has exploited NPM’s use of “Remote Dynamic Dependencies” to flood NPM with 126 malicious packages that have been downloaded more than 86,000 times. Some 80 of those packages remained available as of Wednesday morning, Koi said.

A blind spot

“PhantomRaven demonstrates how sophisticated attackers are getting [better] at exploiting blind spots in traditional security tooling,” Koi’s Oren Yomtov wrote. “Remote Dynamic Dependencies aren’t visible to static analysis.”

Remote Dynamic Dependencies provide greater flexibility in accessing dependencies—the code libraries that are mandatory for many other packages to work. Normally, dependencies are visible to the developer installing the package. They’re usually downloaded from NPM’s trusted infrastructure.

RDD works differently. It allows a package to download dependencies from untrusted websites, even those that connect over HTTP, which is unencrypted. The PhantomRaven attackers exploited this leniency by including code in the 126 packages uploaded to NPM. The code downloads malicious dependencies from URLs, including http://packages.storeartifact.com/npm/unused-imports. Koi said these dependencies are “invisible” to developers and many security scanners. Instead, they show the package contains “0 Dependencies.” An NPM feature causes these invisible downloads to be automatically installed.

Compounding the weakness, the dependencies are downloaded “fresh” from the attacker server each time a package is installed, rather than being cached, versioned, or otherwise static, as Koi explained:

This opens the door to sophisticated targeting. In theory, they could check the IP address of every request and serve different payloads: benign code to security researchers on VPNs, malicious code to corporate networks, specialized payloads for cloud environments. Or play the long game—return clean code for weeks to build trust and pass security scans, then flip a switch and start serving the malicious version.

NPM representatives didn’t immediately answer an email seeking details and asking about the practice.

The dependencies thoroughly scour infected machines in search of all kinds of sensitive information, including:

  • Environment variables showing configurations and other information about the developer’s internal system
  • GitHub, Jenkins, and NPM credentials, which could potentially be used in follow-on supply-chain attacks
  • The entire continuous integration and continuous delivery environment, which is responsible for automating the integration of code changes from multiple developers into a single codebase

The process for exfiltrating the gathered data, Koi added, was “redundant to the point of paranoia.” It relied on HTTP requests, JSON requests, and the establishment of Websockets.

Many of the dependencies used names that are known to be “hallucinated” by AI chatbots. Developers frequently query these bots for the names of dependencies they need. LLM developers and researchers have yet to understand the precise cause of hallucinations or how to build models that don’t make mistakes. After discovering hallucinated dependency names, PhantomRaven uses them in the malicious packages downloaded from their site.

Anyone who regularly downloads packages from NPM should check the Koi post for a list of indicators that their system has been compromised through PhantomRaven. These indicators can be used in system scans to determine whether they’ve been targeted.

Photo of Dan Goodin
Dan Goodin Senior Security Editor
Dan Goodin is Senior Security Editor at Ars Technica, where he oversees coverage of malware, computer espionage, botnets, hardware hacking, encryption, and passwords. In his spare time, he enjoys gardening, cooking, and following the independent music scene. Dan is based in San Francisco. Follow him at here on Mastodon and here on Bluesky. Contact him on Signal at DanArs.82.
64 Comments
Staff Picks
jdale
You're not the only one. Aren't writers supposed to define an acronym the first time they use it?

And I know this is a tech site, but not everyone who reads a tech site is a software developer.
That it's an abbreviation is not really relevant here. It sort of stands for "node package manager" but that really doesn't tell you anything.

https://en.wikipedia.org/wiki/Npm
npm is a package manager for the JavaScript programming language maintained by npm, Inc., a subsidiary of GitHub. npm is the default package manager for the JavaScript runtime environment Node.js and is included as a recommended feature in the Node.js installer.[4]

It consists of a command line client, also called npm, and an online database of public and paid-for private packages, called the npm registry. The registry is accessed via the client, and the available packages can be browsed and searched via the npm website. The package manager and the registry are managed by npm, Inc.


I guess it's another example of why unnecessary javascript should be blocked, even though it makes the net harder to use and navigate. And in this case it's probably exploited necessary javascript as well as unnecessary javascript.