Malicious NPM Development Kit

A brief history of undetected attacks and where to find them

Joel Thoms
Bits and Pieces

--

“this is fine” meme

This post helps promote awareness and security in the open source.

The Yin and Yang of NPM

Without a doubt, NPM is an amazing thing that happened to JavaScript. NPM has been a godsend to the open source community providing an easy way to share code across the world. It was a trailblazer in collaborative and modular JS development, paving the way for everything that comes next including futuristic and modern JS code sharing platforms like Bit. It’s still is.

But… and this is a BIG BUT. NPM’s success came with a price, as it became an exploitable attack vector into our networks and PCs. This isn’t to say that we shouldn’t share modular code; on the contrary. But, we have to be minded to the risks and manage them while doing so. Let’s review a brief history.

left-pad

In case you are just getting out of your coma, the left-pad fiasco was big. The left-pad developer removed the package, which 1,000’s of other projects depended on, breaking the internet. This ended up getting fixed by NPM by restoring the project (against the developer’s wishes) and causing a lot of controversy along the way.

But what if instead of removing the package, the developer chose to slip in a few lines of malicious code? Code that didn’t produce an error. Code that wasn’t so easy to notice.

left-pad was a warning.

event-stream

If left-pad was a warning, event-stream should have been a bullet to the knee.

event-stream included a malicious package that was searching for and targeting Bitcoin wallets.

These types of attacks will increase, they will become more sophisticated, and they will go undetected.

event-stream has been patched and the malicious dependencies removed. But that was after it had already been downloaded millions of times.

At the time of this writing, event-stream is still downloaded 1.3M times a week.

node_modules

node_modules are a disaster. Have you ever looked inside?

diagram showing node_modules is more dense than the sun, a neutron star, or a black hole

Nobody knows what is in there. Heck,create-react-app installs 1,839 packages at a size of 531M.

This is the perfect environment for an attack. Malicious code can easily go undetected in this ocean of files.

One guy did look inside his node_modules, and the things he found were shocking. (Okay, I’ll be honest here, when I didn’t catch that it was satire. It is still an entertaining read.)

NPM Scripts

NPM Scripts is another one of those tools that make JavaScript development a delight. The ability to hook into actions and run commands is very powerful.

But this is where the real danger begins.

NPM contains a new command NPX. this command let’s you, in a single command, execute a remote NPM package. This code will execute using the permissions of the account running it.

An example of npx is the command: npx create-react-app my-app. Running this command will create a new React App named my-app.

This new npx command has prompted many “novelty” packages. By running the command: npm bitandbang, you will be presented with Tierney Cyren’s business card.

This is cute until you learn you just ran untrusted code. You don’t know him and you definitely didn’t look at his code before running it. But you ran it on your machine and it ran with the full permissions of your account.

This NPM Business Card project has spawned multiple copy-cats. Don’t trust any of them.

“this is not fine” meme

Let’s see what level of damage we can do

Okay, so far this has been all anecdotes and stories. Let’s roll up our sleeves and do dirt.

Run this command:

# Run me! 😉
npx maleficent

No seriously, run it. I created the maleficent npm package. You won’t fully understand the gravity of this situation until you run this command. I’m waiting…

Maleficent is a small demonstration of what could be. Maleficent harvests your environment variables, OS details, Network information, AWS Credentials, NPM Credentials and SSH keys.

(Leave a comment below to suggest more things for maleficent to gather.)

After running npx maleficent, you’ll find a file called malificent.json in your directory. A malicious hacker, would have sent this file to himself and you would have been none the wiser.

I have output this file so you can open it and reflect on what might happen if that file got into the hands of some hacker.

If you are too 🐤 chicken to run the command, you can see what the output malificent.json looks like here:

Maleficent will also run itself when you run the very common npm install.

npm install maleficent

You wouldn’t expect anything to be executed here… but it does. Check your directory, you’ll find a malificent.json.

Vectors to Attack

The easiest way to get your exploits onto other people’s computer is to takeover existing packages.

Locate a package that other’s rely on and simply ask them to take over the project. Most developers create these libraries in their spare times and don’t have time to maintain them. They’ll be more than happy to have you takeover.

This is exactly what happened with flatmap-stream.

You will now have access to all projects that use this library as a dependency.

Another attack vector is to name your package similar to other popular packages and hope to catch misspellings. This is what happened to the cross-env attack.

If you don’t mind playing the long game, you could create a helpful utility and wait for the installs to grow organically. Even the smallest packages will be installed a few hundred times a week.

It has already begun

The attacks have already begun and until the system is changed, nothing will stop them from continuing.

Because there is no way of detecting these attacks, all we can do is cross our fingers and hope our company isn’t affected, our projects aren’t affected, our machines aren’t affected.

Bad things don’t happen to us. Bad things happen to other people.

Reflecting on the impact

Installing an NPM typically installs dozens of other packages. node_modules grows exponentially with the number of packages installed. It’s common to have thousands of packages installed in a typical app.

Code can execute during an npm install. This code could harvest credentials or install back doors and trojan horses.

npm install runs as your user. So it will have full access to your home directory and any other files your user also has access to.

npm install runs on CI/CD servers. What secrets are you storing in your Environment Variables that could be harvested?

Okay crap 💩, can I truly trust any machine I have ever run npm install on? No.

So where do we go from here?

David Gilbertson has come up with an idea of NPM Package Permissions. This seems extreme at first glance. But all systems that are open by default eventually have to change to closed by default. I still remember the days computers were plugged directly into the internet without any firewalls.

Another option is to run a VM like Docker to run npm installs and builds. This would prevent malicious code from accessing sensitive data on your machine as it would only have access to the VM.

Spend time researching and investigating the packages you are installing. Also check their dependencies. Use a service like snyk or Greenkeeper to manage dependencies and vulnerabilities. (Recommend more services like these in the comments) Don’t install a Bitcoin wallet on a machine that has ever had npm installed on it.

“Malicious Modules — what you need to know when installing npm packages” by Liran Tal https://link.medium.com/RIv2Ac8j1U

Continue the Conversation

I would love to hear your thoughts in the comments. Is this something that concerns you? What do you think we should do about it? How can we fix this?

Continue the conversation in the comments below or @joelnet on Twitter.

Cheers!

--

--

Computer Scientist and Technology Evangelist with 20+ years of experience with JavaScript!