How to protect yourself from npm

What’s the worst that could happen after npm install?

Timo Tijhof
Sep 12 · 6 min read

When you open an app or execute a program from the terminal,
that program can do anything that you can do.

In a nutshell: Imagine if your computer were to disappear in front of your eyes and re-appear in front of mine. Still open. Still unlocked. What could I do from this moment on? That is what an evil program could do.

Upon running npm install, you may be downloading and executing hundreds of unknown programs.

1. What is at stake?

2. How does it compare to other package managers?

3. What can you do about it?


Two surveillance cameras on a lamppost with a clear blue sky behind them.
Two surveillance cameras on a lamppost with a clear blue sky behind them.
Photo by Raysonho

Programs from nice people sometimes ask for your permission. This is because a developer choose to do so.

There may also be laws that could punish them if they get caught choosing differently.


What about programs of which the authors choose differently? Well, such program could do quite a bit.

  • It could access any of your files, modify them, delete them, or upload them. This also applies to the internal files used by other applications.
  • It could install other programs in the background.
  • It could talk to other devices linked to your home network.

What is at stake

  • The cookies in your web browser.
  • Desktop applications. Chat history, password managers, todo lists, etc. They all use files to store the text and media you send or receive.
  • Digital media. Your photo albums, home videos, and voice memos.
  • SSH private keys, GPG key rings, and other crypto files used by developers.
A red face in a white rectangle made of nanoblocks, resting on a silver Apple keyboard.
A red face in a white rectangle made of nanoblocks, resting on a silver Apple keyboard.
Photo by DaraKero_F / CC BY 2.0

Browser cookies

They could then read any e-mail you’ve ever received or sent stored there. It could also delete any. (Got a backup?) They can naturally access future e-mails as well. Like the ones you get from “Forgot password” buttons. They could also hide any trace of these (e.g. filter rules).

This affects any website you use. Social network? Access to any post or DM — regardless of privacy setting. Company e-mail, Google Drive? That too.

Sleeper programs

It could also add local command-line programs that wrap the popular sudo and ssh commands, to make them do a little extra behind the scenes. Next time you run sudo <something> to perform an administrator action and enter your password—you may have given away full system access. Deploying some code? Running ssh cloud.someplace.special might let the attacker tailgate along with you, opening one shell for itself and another for you.

Statue of King Louis XIV on a horse with a red blindfold over his eyes. Taken in Paris, France.
Statue of King Louis XIV on a horse with a red blindfold over his eyes. Taken in Paris, France.
Photo by BikerNormand / CC BY-SA 2.0

Local web server


Is this an npm problem?

Upon seeing the url and the bash invocation, you have a choice: Trust the publisher (the url), or trust the script (download, review, then decide whether to run). The result is generally predictable and without hidden dependencies.

Other package managers

Earth is small compared to Jupiter. Jupiter is roughly 11 times larger.
Earth is small compared to Jupiter. Jupiter is roughly 11 times larger.
Image by NASA / Public domain

The scale has changed the game

Dependency graphs

The ESLint package has 118 npm dependencies [5]. Eleventy, a popular static site generator, requires 555 dependencies (Explore this dependency graph). Each one of these may run arbitrary shell commands from the terminal both during the installation process, after later when using the tool.

I get it. Now, what can we do about it?

Isolation

Close-up view of network cables and LED lights on servers in a date-centre.
Close-up view of network cables and LED lights on servers in a date-centre.
Photo by Victor Grigas / CC BY-SA 3.0

My base image uses Debian and comes with Node.js, npm, and a few other utilities (such as headless browsers, for automated tests). I use a bash script to launch a temporary container, based on that image. It runs as the unprivileged nobody user, and mounts only the current working directory.

From there, I would run npm install and such. The only thing it interacts with is the source code and local node_modules directory for that specific project. It isn’t given access to any other Git repos, desktop apps, browser cookies, or crypto files. And, once that terminal tab is closed, the container is destroyed.

I’ve published the script I use at github.com/wikimedia/fresh. I don’t recommend using it outside Wikimedia, however. Create your own instead. The repository explains how it works.

Other options for isolating your environment:

  • Speed and flexibility: Use systemd-nspawn or chroot. This takes more work to setup, but provides a faster environment than Docker. In terms of security it is comparable to Docker. Read more systemd-nspan on ArchWiki.
  • Security and ease of use: Use a virtual machine (e.g. VirtualBox/Vagrant). This is more secure by default and offers a GUI for controlling what to expose. The downside is that VMs are significantly slower.

Fewer dependencies

Question yourself and question others before introducing new dependencies. Perhaps even encourage maintainers of your favourite packages to Reduce the size of their dependency graph!


See also

Further reading


Also published on timotijhof.net.

Thanks to Kosta Harlan and Tim Starling

Timo Tijhof

Written by

Performance Team at Wikipedia • timotijhof.net

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade