Managing Security, Reliability and NPM

How can we avoid depending on garbage or malicious packages?

Every time we generate a new React app, we add thousands of packages from thousands of open source contributors around the globe. These packages save us valuable time that could have been lost solving already-solved problems in vanilla JavaScript.

“People think that computer science is the art of geniuses but the actual reality is the opposite, just many people doing things that build on each other, like a wall of mini stones.” — David Knuth

The upside to this dependent-heavy ecosystem is that it saves us time, energy and countless headaches. Dependencies are how the coding community keeps itself DRY. On the other hand, this ecosystem requires a certain degree of trust. Given that few of us have time to go through and examine, for example, the over 41,000 files that a fresh install of Babel alone entails (and that’s just Babel!) we are essentially trusting a large number of foreign developers not to have included malicious, insecure or inefficient code in their packages.

In the past, this trust has occasionally broken down.

The Leftpad Fiasco

Back in the heady days of 2016, while you were mourning the loss of Harambe and pondering dat boi, a man name Azer Koçulu broke the Internet.

Leftpad in its entirety

Embroiled in a copyright battle with Kik, Koçulu ragequit node and removed all of his NPM managed modules (over 250). Unfortunately one of his modules, left-pad, was more than a little bit popular — it had been fetched millions of times.

Normally when a module is unpublished, steps are taken to ensure that projects depending on that module do not break. Koçulu did not take those steps. As a result, thousands of apps across the globe broke simultaneously until NPM un-un-published left-pad in order to end the chaos.

This debacle raised a good deal of talk and controversy surrounding dependencies and third party code. After all, no one wants their code to break just because someone else decided to pull a package.

Unfortunately, things get worse.

The Trojan Problem

In January of 2018, web developer and blogger David Gilbertson published a blog titled “I’m harvesting credit card numbers and passwords from your site. Here’s how.” In his blog, Gilbertson outlined the steps an unethical developer could take to insert and conceal a trojan into the package ecosystem that would grab credit card data from any site that unwittingly depended on it.

An unethical hacker introduces vulnerabilities into the node ecosystem

The problem stems, at least in part, from the fact that code hosted in NPM need not match the source code that is publicly visible on GitHub. While users can go through their own npm_modules folder and check for vulnerabilities, this folder is usually impractically large for manual monitoring and some basic cryptography can be used to conceal malicious code.

Gilbertson’s article shook the Node community to its core. Once again, much ink was spilled, including from skeptics. That said, most agreed that Gilbertson had revealed an important potential source of security leaks.

Don’t Panic

For starters, steps have already been taken in the past year to secure the node ecosystem. In April 2018, NPM released npm-audit, which assesses packages for known security flaws. npm-audit works by checking your project against vulnerabilities collected by ^Lift Security’s Node Security Platform.

This was widely regarded as a good move and a huge improvement.

That said, not all developers are pleased with the state of NPM security, leading to projects like SNPM. (For more Node.js work by Wilk, check out Thanc, an exercise in politeness.)

What You Can Do

Some guidelines on maximizing NPM security and minimizing breaches.

Functions Are Not Packages

For starters, packages can only introduce vulnerabilities or malicious code into your project if they’re included in your project. The good news is, you have full control over what dependencies you want to rely on.

In general, limit dependencies as much as possible to avoid bloat and excessive trust on third party developers. Dependencies should be large packages that save you serious amounts of time and effort and would be impractical to write by hand. One good rule of thumb is: Functions are not packages. A simple function such as left-pad, isArray or is-positive-integer that can be written manually in a few minutes is something that you should be writing and storing yourself. If you’re struggling with a function, consider googling and learning from other people’s functions instead of directly including them as minified dependencies.

Research Products Built To Improve NPM Security

The aforementioned SNPM is only one way to improve the security of your project. Other tools like Certified Modules and Snyk are options for adding additional layers of security to your Node environment. Finally, make use of NPM’s new npm-audit tool. Do your research.

Serve Forms Inside iFrames Built On Native Code

Finally, the most foolproof way to take power from trojans in your app is to serve up important forms, such as credit card forms, in independent iFrames written in your own hand-crafted vanilla JavaScript. This way, you can quarantine secure forms from the rest of your app and ensure that secure user data is only interacting with native code that you 100% trust.

Of course, it’s now your responsibility and your responsibility alone to make sure that this data is handled, transferred and stored responsibly. And that’s a subject for another day.

P.S. While we’re at it, did you know that every installation of Babel includes a picture of Guy Fieri?