npm in a box: Containerizing package managers for security.
I’ve written about Docker quite a bit recently. This flurry of activity about Docker is directly related to a post by Andrew Welch, Dock Life: Using Docker for All The Things! He describes how to use aliases and Docker containers to run apps typically installed on a developer’s computer without needing to install software directly on the machine.
I have wholeheartedly embraced the methodology. The idea of running development tools in Docker containers for basic utilities coincided with the arrival of my new computer, a MacBook Pro. Although I rely on Node.js, npm (frustratingly, not capitalized), and a bunch of other development tools, I have not installed any of them on my laptop and can still use them every day without issue. I haven’t even installed Homebrew, “the missing package manager for macOS (or Linux),” a tool Mac users typically rely on to install various software.
Andrew mentions many benefits of this approach. I won’t restate them here. This post is primarily about an additional benefit: securing your computer.
Are shared resources a problem?
The shared-resources ecosystem we currently rely on is incredibly useful. We can include a well-written library into a project with a few commands. For example, I wouldn’t want to write an ajax library every time an app needed to talk to an API. I just use Axios and move to the next task at hand.
There are a variety of shared ecosystems. I regularly rely on 2 of them, composer for PHP packages and npm for Javascript packages. Although I’ll frame this article with references to the security of npm, since it is familiar to me, the security benefits of containerization can be applied broadly.
A closer look at npm
I think npm is a fantastic resource, but I believe it is even better when used inside a Docker container. Let’s outline why this is the case.
Popularity provides a wide attack surface for malware to make an impact and npm is very popular. At the time I write this, March 30, 2022, the npm homepage reports that there were 42,843,361,218 downloads from npm last week.
That’s a significant attack surface. Reporting suggests that npm is a “playground for malicious actors.”
JavaScript is the most commonly used programming language globally, and 68% of developers depend upon it to create rich online functionality. With an average of 32,000 new npm packages published per month in 2021, attackers are using the popularity of npm to hide their nefarious behavior and launch attacks. In just six months, more than 1,300 malicious npm packages have been identified and reported by WhiteSource Diffend, making it vital for developers to understand what attackers are doing and how they can remediate issues without slowing down the development process.
That sounds pretty scary. We can look beyond white papers and for some real-life examples.
- NPM package with 3 million weekly downloads had a severe vulnerability — Ars Technica
- Over 200 Malicious NPM Packages Caught Targeting Azure Developers — The Hacker News
- Malware authors target rivals with malicious npm packages — ZDNet
- Malicious npm packages are stealing Discord tokens — ZDNet
- Sabotage: Code added to popular NPM package wiped files in Russia and Belarus — Ars Technica
This is just a fraction of news articles on the topic. npm and other package managers present fertile ground for people wishing to bad things at scale. Why? Because it’s built on trust and there are some untrustworthy characters, even if they are small in number.
Fear not! Ok, maybe, just fear somewhat.
npm is aware of the problem and already has plans for dealing with security threats. A section of their site is dedicated to securing the ecosystem. There is an auditing process in npm and a process for reporting malware. They likely have other non-public plans in place as well.
The npm security processes help fix problems on a network level. If a package is compromised and makes its way into the global registry, npm can pull the package from the registry when it becomes known. It can also warn you in the command line of discovered vulnerabilities in the packages you use. Github has Dependabot alerts to also help you identify these problems and correct them. These are good efforts but they deal with problems after they’re discovered.
Use Docker to protect your local machine
There is still the possibility that you will install a malicious piece of code before a threat has been identified. You can use Docker to help contain problems.
Let’s imagine a scenario similar to the one mentioned in the Sabotage link above.
A developer has been caught adding malicious code to a popular open-source package that wiped files on computers located in Russia and Belarus as part of a protest that has enraged many users and raised concerns about the safety of free and open source software.
Instead of deleting “files on computers located in Russia and Belarus” in this imaginary scenario, malicious code erases 20 random files it comes across. The files at risk are anywhere that npm can access.
Scenario #1: Global installation of your dev tools
You’re encouraged to run your dev tools on your machine globally. Why are you doing this?
Look at the Downloading and installing Node.js and npm guide. How do you install npm? There’s a simple command for that.
npm install -g npm
What about upgrading an installation of npm? Another simple command. Handy! (BTW, I’m encouraging you to not to do this! Don’t consider this section as instruction on what to do.)
npm install npm@latest -g
What does -g
mean in each of those commands? Global.
The documentation actively encourages you to do global installation of your tools so, in our first scenario, that’s what you’ve done. You followed instructions. Since this is the normal way of doing things, your dev server may also be running globally on your machine. This global context is what our theoretical malicious package will use at its attack surface, randomly deleting files it finds. Your entire computer is open for exploitation.
You’ve installed the malicious package from npm and now 20 random files on your computer are simply gone. It’s easy to imagine the havoc the code could cause.
Scenario #2: Dev tools installed in a container
If you’re running your development tools as Andrew suggested in Dock Life: Using Docker for All The Things! you are in a much better position in my opinion. Files in the project you’re working on still are potentially vulnerable.
This is still a bad situation. The files in your project face potential deletion or alteration. You could lose 20 files in your project when the malware attacks.
Since this is a development project, all of these files are likely under source control. You will have a remote git repository that contains the complete history of this project before the infection.
Since you’re running your dev tools in Docker containers, you can shut them down and destroy them. You can pull down fresh copies of the last working version of your code from your git repo and pick up from the point the malicious code was installed.
Security issues still remain
Using Docker containers for your dev tools does not solve the global shared resource pool problem. There are still many ways things can go wrong, but using your tools in containers can limit the potential damage you face.
Tradeoffs
Before I wrap this up, we should talk about the downsides.
Public reaction? Mixed.
If you read through the comments posted at the end of Andrew’s article, you’ll see the comments posted are mixed as best. I’ll summarize the comments in a positive way:
It’s not the same as installing dependencies globally and there are tradeoffs sometimes in not having apps running globally on your system.
As I mentioned at the beginning, I use my dev tools in containers without issue, but it does require some changes in your behavior. I am used to the workflow, but I think it requires understanding how containers work.
If you’re interested in trying this out without diving fully into the deep end, check out my post Making a Basic Docker Image. At the end of that post, you will have a single “contained” command-line tool, tree
not installed on your computer but still usable on your computer. Also be sure to read Dock Life: Using Docker for All The Things!.
Good luck. If you have thoughts, please feel free to reach me on Twitter, @johnmorton.