5 NPM and Node tips to make your dev machine safer
Tags: javascript, node, react, security
Published: 2020-05-28 13:39:19

NPM is used as a convenient cross-platform package manager for [a lot of developer tools](https://hackernoon.com/the-best-of-npm-install-g-9ab9d749eeb1). For many tools, the defacto way to install is **`npm install -g $TOOL`**. But installing anything via npm allows it to run untrusted code on your machine.

Here are a few tips to minimize the risk:

### 1. NEVER run npm as sudo/root

[Node's official documentation](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally) recommends not installing global packages as sudo/root. If you have already installed node through `nvm` ignore this step. If you use a system installed `node` e.g using Ubuntu's apt-get, read through **[this guide](https://github.com/sindresorhus/guides/blob/master/npm-global-without-sudo.md)** for Linux/Mac or [npm-g-nosudo](https://github.com/glenpike/npm-g_nosudo) which is a shell script for Linux. 

#### If you are lazy (like me), here's a summary from the linked guide:
```bash
mkdir -p "${HOME}/.npm-packages" && npm config set prefix "${HOME}/.npm-packages"
```
Add this to your `.bashrc` or `.zshrc`:
```
NPM_PACKAGES="${HOME}/.npm-packages"
export PATH="$PATH:$NPM_PACKAGES/bin"
# Preserve MANPATH if you already defined it somewhere in your config.
# Otherwise, fall back to `manpath` so we can inherit from `/etc/manpath`.
export MANPATH="${MANPATH-$(manpath)}:$NPM_PACKAGES/share/man"
```

### 2. Install/Use node using `nvm`

[Node's official documentation](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally) recommends installing node as an unprivileged user using a node version manager.

Here are the steps:
- Install [nvm](https://github.com/nvm-sh/nvm). This does not work for Windows, use [nvm-windows](https://github.com/coreybutler/nvm-windows) which is a totally different project from nvm.
  - Unfortunately, `nvm` suffers from the curl pipe to bash install as its main way to install.
  - If you have git installed on your machine, you can also directly clone it using the following steps:
    - `cd "$HOME" && git clone https://github.com/nvm-sh/nvm.git .nvm`
    - `cd "$HOME/.nvm" && git checkout v0.35.3 && . nvm.sh`
    - Add to your .bashrc or .zshrc:
```
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
```
- `nvm install --lts` or whichever version of node you need.
- `nvm use node`
- To use a node version by default, `echo "lts/*" > "$HOME/.nvmrc"`

### 3. List all your globally installed npm packages and remove any unnecessary ones

Listing global packages is done with **`npm ls -g --depth 0`**
Remove any unnecessary packages with **`npm uninstall -g $TOOL`**
You can check your shell history/scripts folders to see if you actually use many of the global packages.

### 4. Audit your packages
Run **`npm audit`** in your project regularly to see if [any dependencies are vulnerable](https://docs.npmjs.com/auditing-package-dependencies-for-security-vulnerabilities). This only works for your development projects, not global packages.

#### [A (hacky) way](https://stackoverflow.com/a/53619858) to `npm audit`  global packages:
- Run `npm`. The last line will show the folder of the global npm packages e.g `$HOME/.npm-packages/lib/node_modules/npm`
- Go to `$HOME/.npm-packages/lib` and run `npm init -y` and then run `npm i --package-lock-only`. These steps are required as `npm audit` checks for `package.json` and `package-lock.json`
- Now run `npm audit`. Remove any dependencies which have high or too many moderate vulnerabilities. These could either be malicious or unmaintained tools.
- Remove the `package.json` and `package-lock.json` after the audit 

### 5. Use `npx` to run executables

Many times, it is not necessary to have a tool installed globally e.g `create-react-app`. Node 6+ comes with `npx` which allows you to temporarily download and run scripts. The benefits of using `npx` over `npm install -g` are beautifully explained in [this post](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b).

A gist of the article:
> Calling npx <command> when <command> isn’t already in your $PATH will automatically install a package with that name from the npm registry for you, and invoke it. When it’s done, the installed package won’t be anywhere in your globals, so you won’t have to worry about pollution in the long-term.

> This feature is ideal for things like generators, too. Tools like yeoman or create-react-app only ever get called once in a blue moon. **By the time you run them again, they’ll already be far out of date, so you end up having to run an install every time you want to use them anyway.**

### Bonus : Use Deno for developer tools

I think a project like [deno](https://deno.land/) with good sandbox capabilities and [limited permisisons](https://deno.land/manual/getting_started/permissions) is the best choice for a lot of developer tools currently made using Node. Read [this post](https://www.jeremymorgan.com/blog/programming/what-is-deno/) for more details on why everyone is talking about Deno.


### Conclusion

Does this solve all security issues of `node`/`npm` on your machine? No! There are a [lot](https://blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident) [of](https://blog.npmjs.org/post/185397814280/plot-to-steal-cryptocurrency-foiled-by-the-npm) [ways](https://blog.npmjs.org/post/175824896885/incident-report-npm-inc-operations-incident-of) in which a malicious attacker can compromise your machine/project. This only prevents a bad npm tool from getting root access and removes globally installed npm tools with known insecure dependencies.