A Malicious Module on npm

Earlier this week a package called rimrafall was published to npm. This package had a preinstall hook that executed the command rm -rf /*. It was created on 01/26/2015 at 15:28 and immediately posted to Hacker News and then it was unpublished from the registry by npm at 17:06 -- giving it a lifespan of less than two hours.

The goal behind this example was to raise awareness of potential insecurities with how npm installs packages, and to highlight the necessary steps that are required to mitigate a rogue package from doing harm.

There are a couple of topics worth close examination in this post:

  • The topic of security disclosure and how to disclose information responsibly
  • The responsibility of both developers and enterprises who use open source software

Full disclosure has its place, but it's not the first step.

Over the years I've found and disclosed my share of bugs and I have usually taken the responsible disclosure route where you tell the vendor, let them fix it, and then publicly release the details. However, I've also dropped my share of "well I just want to feed my ego now" bugs, and it has taken me years to realize the effect of doing this.

There is an interesting yin and yang to discovering security vulnerabilities. A security researcher hits a high when a vulnerability is found, and at the same time the developer responsible for creating the code hits an emotional low. Disclosure is the only thing that's going to give the finder another hit to keep the high going, and that excitement is fleeting at best. In most cases, the discovery of the bug feeds the ego of the researcher, but there is little long term investment in the code base. Naturally, this can often feel like a "drive by attack" to a developer who has invested a lot of time and energy into building an application.

Full disclosure does have its place when there has been no action from the vendor, and not communicating the problem to the community would be negligent on the finder's part.

In this case, however, there was no attempt by João Jerónimo to communicate with the npm community, to try and address it before going full press by creating and publishing a package that was, in fact, malicious in nature. I believe he was well intentioned to highlight this risk with npm, but it was executed in bad form.

If you are a developer or researcher, and you are unsure about how to handle reporting a security issue, or are not getting the response you feel you should be getting, talk with us at the Node Security Project. We would be happy to help guide you through the process.

You are responsible for what you require.

I've said it once and I'll say it again -- you are responsible for what you require. This is not the fault or failure of npm.

npm provides a set of tools to enable the module community to exist and thrive. They do their best to not police content, however when code exists that is directly malicious in nature, it gets removed (as rimrafall was).

This is not the first, nor will it be the last malicious package we will see on npm (or any other package distribution system for that matter).

Each published version of a package technically represents a threat to your system and as such, you should have a process in place to validate and vet what you and your developers want to use. While I understand that might be a daunting and ocean boiling process, you can't leave the quality of the code up to developers who are outside your sphere of influence.

So how do I protect myself when I npm install something?

npm allows the module author to specify a number of hooks to be run at different stages of the install or uninstall. These hooks are run by default when you perform these npm actions.

To know if a module you are about to install has hooks that will run, use the command npm show $module scripts (thanks to @naholyr for reminding me of this.)

Inspect the source before you npm install it

To make sure these hooks aren't run when you want to review a package, don't npm install it, but look at the source code in its repository first. Note that the repository does not have to represent the package in any way shape or form. A malicious package will most likely not show its cards here or even have a repository.

You can download the tarball of the module directly and inspect it.

http://registry.npmjs.org/MODULENAME/-/MODULENAME-VERSION.tgz

Example: http://registry.npmjs.org/helmet/-/helmet-0.6.0.tgz

Install it safely with --ignore-scripts

If you do just want to install it from npm, the easiest way is to use the npm install option --ignore-scripts which doesn't protect you from malicious or native code in the module, but does stop the script hooks from executing immediately on installation.

Make sure you're installing the right thing

Another issue is that of typo'd package names.

I did some research a few years back on the risk of installing the wrong module. Do developers actually make typos in module names they wish to install? Sure enough, they do. I was given access to review the 404's for the npm registry logs, and found some very interesting data.

Based on the top 100 most depended upon modules at the time, I generated common typo's using typojs and looked to see how many people had tried to install the typo'd modules instead of the correct ones. There are a few interesting results that bubbled up to the surface.

coffee-script had the following high scoring typo's - coffeescript: 20354 - coffe-script: 3171

uglify-js - uglifyjs: 13315

socket.io - socketio: 7780

Notably, it was the modules with punctuation in them that tended to be the most commonly typo'd. Fortunately these modules don't exist, so trying to install them will just error on you, but it could be a lot worse if someone published a malicious package there instead. The point being that even if you use --ignore-scripts you still might end up with a malicious package on your system.

Stay safe!

With all this in mind, hopefully, you can now put processes in place and take responsibility for the modules you require.

If you would like a helping hand, check out requireSafe. With requireSafe, the ^lift team will proactively monitor and audit the modules you depend on for vulnerabilities and risks, and notify you as soon as we find them. We'll be announcing more about requireSafe in the coming months.

You might also enjoy reading: