DEV Community

Jimmy Roberts
Jimmy Roberts

Posted on

Keeping Your App Secure with NPM

As developers, we prefer to use opensource repositories to improve our development process instead of reinventing the wheel over and over again.

While this is convenient and can save lots of time in development, apps can be exposed to a variety of security risks.

How can this happen?

There are lots of ways this can happen and I don’t have enough time to list them all. However, one way would be that someone is reviewing a Pull Request and doesn’t notice some malicious code and approves the Pull Request, subsequently introducing a worm to the repository that can then spread and cause damage.

Typically repositories follow the semantic versioning standard (Though some may use sentimental versioning; please don’t), meaning that there will be a bump in the PATCH version.

Whenever you install a repository as a dependency, it will be added to your package.json with the version number at the time of the install.

E.G.) “repo”: “^3.0.0”

That ^ can be what compromises your build. It means anytime there is a new version, it will be installed as long as the MAJOR version is below 4. (It can also be PATCH only - ~, or any version - *)

So if the compromised version ends up being 3.6.4 then the next time you run npm install, you will, unfortunately, add the worm to your repository.

How can this be prevented?

Firstly, stricter code reviews. Though that isn’t the fix all.

The best defense, in my opinion, is to save the exact version in your package.json. You can manually go in and change the version to look like: ”repo”: “3.0.0”.

You can also install the dependency with the --save-exact or -E flag.

As well as run a command that will make it default on future installs:

npm set save-exact true

While this will prevent you from automatically getting bug fixes or new features on dependencies, saving the exact version will help prevent you from being vulnerable to human error or maliciousness.

What about my dependencies` dependencies?

Chances are your dependency has dependencies on other repositories as well. So you may want to consider locking them down too.

You can do this with npm shrinkwrap. If you’re not familiar with this, it is exactly like package-lock.json except you can publish it. If you already have a package-lock.json it will be replaced with npm-shrinkwrap.json. If for some reason both are in your repository, the npm-shrinkwrap.json will take precedence.

One last thing…

NPM automatically runs an audit on your dependencies when you run npm install. If you have a dependency that has been compromised, NPM should alert you of the vulnerability. You can then run npm audit fix, and if there is a fix published already, it will install updates to the vulnerable dependency.


TL;DR

Update your package.json to only use exact versions to prevent malicious code or bugs from affecting your repository.

P.S. Locking in the version also prevents the classic “Well, it works on my machine, so it’s not broken.” comment, because all node_modules will be the same version on all machines.

If you think I've missed something, please let me know!

Cheers!

Top comments (0)