With over 200k packages, npm is the world’s largest registry of open source packages. It serves several million downloads each month. The popularity of npm is a direct result of the popularity of JavaScript. Originally npm was the package manager for Node.js, the server-side JavaScript runtime. Since Node.js developers mostly follow the Unix philosophy, the npm registry contains many very small libraries tailored to a specific purpose. Since the introduction of Browserify, many of these libraries suddenly became suitable for use in the web browser. It has made npm not only the package manager for Node.js, but for the entire JavaScript ecosystem. This is why npm is not an abbreviation of Node Package Manager, but a recursive bacronymic abbreviation for "npm is not an acronym". Wow.
If you do any serious JavaScript development, you cannot go without libraries, so npm is an indispensable resource. Any project of meaningful size is quickly going to rely on several dozen libraries. Considering that these libraries often have a handful of dependencies of their own, your application indirectly depends on hundreds of packages. Most of the time this works out quite well, but sometimes things aren’t that great. It turns out that keeping all of these dependencies up to date can be quite a challenge. Even if you frequently check your dependencies for updates, there’s no guarantee that your dependencies’ authors will do the same. With the pace at which new JavaScript packages are being released, it’s close to impossible to keep everything up to date at all times.
Most of the time it’s not a problem to rely on an older version of a package. If your package works fine with an outdated dependency, there’s no compelling reason to upgrade. Why fix something that isn’t broken? Unfortunately, it’s not so easy to tell if it is. Your package may have been broken without your knowledge. The problem is in the definition of "broken". You could consider it to mean your application doesn’t work in some way, but what about the non-functionals? Did you consider the fact that you may be relying on packages that introduce security vulnerabilities into your system?
Like any software, Node.js and JavaScript aren’t immune to security issues. You could even consider JavaScript inherently less secure because of its dynamic nature. The Node Security Project exists to address this issue. It keeps a database of known security vulnerabilities in the Node ecosystem and allows anyone to report them. Although NSP provides a command line tool to check your dependencies for vulnerabilities, a new company called Snyk has recently released a tool to do the same and more. Snyk, short for "so now you know", finds security vulnerabilities in your entire dependency tree based on the NSP database and other sources. Its CLI tool is incredibly simple to install and use. Just npm install snyk
and off you go. You can run it against your own project, or against any npm package:
[code]
snyk test azure
✗ Vulnerability found on [email protected]
Info: https://app.snyk.io/vuln/npm:validator:20130705
From: [email protected] > [email protected] > [email protected] > validator@~3.1.0
No direct dependency upgrade can address this issue.
Runsnyk protect -i
to patch this vulnerability
Alternatively, manually upgrade deep dependency validator@~3.1.0 to [email protected]
…
Tested azure for known vulnerabilities, found 32 vulnerabilities.
[/code]
It turns out the Node.js library for Azure isn’t quite secure. Snyk can automatically patch the vulnerability for you, but the real solution is to update the azure-common package to use the newer version of validator. As you see, most of the security issues reported by Snyk have already been fixed by the authors of the affected library. That’s the real reason to keep your dependencies up to date.
I think of Snyk as just another type of code quality check. Just like your unit tests, your build should fail if you’ve accidently added an insecure dependency. A really simple way to enforce it is to use a pre-commit hook in your package.json:
[code language="javascript"]
"scripts": {
"lint": "eslint src test",
"snyk": "snyk test",
"test": "mocha test/spec",
},
"pre-commit": ["lint", "test", "snyk"]
[/code]
The pre-commit hook will automatically be executed when you try to commit to your Git repository. It will run the specified npm scripts and if any of them fail, abort the commit. It must be noted that, by default, Snyk will only test your production dependencies. If you want it to also test your devDependencies you can run it with the--dev
flag.