How to use Snyk for fixing node module vulnerabilities
Tags: security, node, npm, javascript
Published: 2020-07-12 20:46:48

[Snyk](https://snyk.io/) is a company that provides security tooling which helps to enable more than 400K developers to find and fix vulnerabilities in open source libraries.

It's primary free offering for Node comes in the form of the `snyk` CLI which is available as an [NPM module](https://www.npmjs.com/package/snyk).

With this CLI you can perform most tasks you need for dealing with third party module vulnerabilities.

You can test for vulnerable packages in your project:

```bash
snyk test
```

Use the guided wizard to ignore, patch or upgrade vulnerable packages:

```bash
snyk wizard
```

And perform patches on vulnerable packages which don't yet have a fix by using Snyk's own fixes developed by their security engineers:

```bash
snyk protect
```

It's that simple to use - let's try running it against the [Express](https://github.com/expressjs/express/) project:

```bash
# Clone Express locally
git clone git@github.com:expressjs/express.git

# Move into the Express project
cd express/

# Run a test using NPX to quickly install and run
npx snyk test
```

You should see something like this in your console:

```console
Testing express...

Organization:      ****
Package manager:   yarn
Target file:       yarn.lock
Project name:      express
Open source:       no
Project path:      express
Licenses:          enabled

✓ Tested 51 dependencies for known issues, no vulnerable paths found.

Next steps:
- Run `snyk monitor` to be notified about new related vulnerabilities.
- Run `snyk test` as part of your CI/test.
```

Awesome! :tada: It's good to know that a project as well-used as Express is free from known vulnerabilities :wink:.

# What happens when there is a vulnerability?

So what happens when a project has a vulnerability? Well, we can actually see this using Express again.

"Wait... I thought Express had no vulnerabilities?" you might think - it is what I just said! :joy:

What the `snyk test` command assured us was there were no known vulnerabilities with the package dependencies. What it didn't check was any of the package's development dependencies, as listed in the `package.json` `devDependencies` section!

In order to get the test (and any other `snyk` command) to consider dev dependencies you have to add the extra `--dev` flag to the command. Let's try this now:

```console
$ npx snyk test --dev

Testing express...

Tested 331 dependencies for known issues, found 5 issues, 9 vulnerable paths.

Issues to fix by upgrading:

  Upgrade eslint@2.13.1 to eslint@4.18.2 to fix
  ✗ Regular Expression Denial of Service (ReDoS) [Low Severity][https://snyk.io/vuln/npm:eslint:20180222] in eslint@2.13.1

  Upgrade hbs@4.1.0 to hbs@4.1.1 to fix
  ✗ Prototype Pollution [Medium Severity][https://snyk.io/vuln/SNYK-JS-HANDLEBARS-567742] in handlebars@4.5.3
    introduced by hbs@4.1.0 > handlebars@4.5.3

  Upgrade mocha@7.0.1 to mocha@7.1.1 to fix
  ✗ Prototype Pollution [Medium Severity][https://snyk.io/vuln/SNYK-JS-MINIMIST-559764] in minimist@0.0.10
    introduced by hbs@4.1.0 > handlebars@4.5.3 > optimist@0.6.1 > minimist@0.0.10 and 1 other path(s)
  ✗ Prototype Pollution [Medium Severity][https://snyk.io/vuln/SNYK-JS-YARGSPARSER-560381] in yargs-parser@13.1.1
    introduced by mocha@7.0.1 > yargs-parser@13.1.1

Patchable issues:

  Patch available for lodash@4.17.15
  ✗ Prototype Pollution [Medium Severity][https://snyk.io/vuln/SNYK-JS-LODASH-567746] in lodash@4.17.15
    introduced by eslint@2.13.1 > lodash@4.17.15 and 3 other path(s)

Organization:      ****
Package manager:   yarn
Target file:       yarn.lock
Project name:      express
Open source:       no
Project path:      express
Licenses:          enabled

Run `snyk wizard` to address these issues.
```

Woah - so Snyk actually found 5 different vulnerabilities in the Express development dependencies (at the time of writing this post!).

Though development dependencies aren't actually shipped with the module when it is installed by users, it is still very important to consider vulnerabilities that occur in them. For example, if your build, lint and testing packages have vulnerabilities you might risk you entire CI/CD pipeline becoming an attack surface from which a malicious party could attempt to either escalate privileges (to gain access to your private CI/CD) or even modify your code resulting in persistent XSS hole or worse!

Fortunately in this case it looks like all the problems either have an upgrade path or a patch available from Snyk. Let's look at how we can resolve these now.

# Using the wizard

The `snyk` CLI comes with it's own wizard for quickly resolving issues using an interactive prompt. This can be run using:

```console
snyk wizard --dev
```

Where we have remembered to add the `--dev` flag here as well to ensure Snyk also considers the dev dependencies! You should see something like below:

![Snyk wizard remediation options for eslint package](https://dev-to-uploads.s3.amazonaws.com/i/2yj64jfzj4ly5a1ysfmk.png)

We can then step through each of the vulnerabilities selecting the desired option - let's upgrade and patch everything we can using the provided options. Once you are done you should see that Snyk has created a new file in your project, a Snyk `.snyk` policy file:

```yaml
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
version: v1.14.1
ignore: {}
patch: {}
```

By the looks of it, it is empty - this usually means that we have successfully removed all of the known vulnerabilities from our project! :tada:

By selecting the various upgrade options, the Snyk wizard has successfully updated our `package.json`, lockfile and `node_modules` to upgrade the affected packages and remove the vulnerabilities. For example, we can see that Snyk upgraded the `eslint`, `hbs` and `mocha` packages in our `package.json`:

![Package JSON with packages upgraded by Snyk](https://dev-to-uploads.s3.amazonaws.com/i/waa36dnjfyg35jqszwbh.png)

# Where Snyk falls down

Let's take our newly upgraded Express and manually downgrade one of it's sub-dependencies, namely [Lodash](https://github.com/lodash/lodash).

Here I'll do this in the `yarn.lock` created (as have been using `yarn`) but this will equally apply if using `npm` and have a `package-lock.json`.

This is the current entry for Lodash:

```yaml
lodash@^4.17.15, lodash@^4.17.4, lodash@^4.3.0:
  version "4.17.19"
  resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
  integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
```

I'm going to downgrade this to `4.17.15` manually by replacing this with the following:

```yaml
lodash@^4.17.15, lodash@^4.17.4, lodash@^4.3.0:
  version "4.17.15"
  resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz"
```

This is just to simulate the point in time where the latest patched version of Lodash isn't out yet and we are using the vulnerable version `4.17.15`. Indeed, running `snyk test --dev` we see that Snyk reports there is a vulnerability:

```console
$snyk test --dev

Testing express...

Tested 314 dependencies for known issues, found 1 issue, 4 vulnerable paths.

Patchable issues:

  Patch available for lodash@4.17.15
  ✗ Prototype Pollution [Medium Severity][https://snyk.io/vuln/SNYK-JS-LODASH-567746] in lodash@4.17.15
    introduced by eslint@4.18.2 > lodash@4.17.15 and 3 other path(s)

Organization:      ****
Package manager:   yarn
Target file:       yarn.lock
Project name:      express
Open source:       no
Project path:      express
Local Snyk policy: found
Licenses:          enabled

Run `snyk wizard` to address these issues.
```

This is interesting because Snyk has correctly identified that there is a vulnerability with that version of Lodash, but instead of suggesting to upgrade it back to `4.17.19` which has the fix, it is suggesting that you patch the vulnerability with a temporary Snyk patch.

What's more is that when we try to use the wizard, it focuses in on the top-level dependency `eslint` saying there isn't a fix for some vulnerabilities...?

![Snyk wizard unable to provide fixes for eslint](https://dev-to-uploads.s3.amazonaws.com/i/iru265mlmmjnl1q5wjji.png)

Next, it finally mentions the Lodash vulnerability that we have introduced, but instead of offering the ability to upgrade, it only gives you the option to patch the issue with a Snyk patch!

![Snyk wizard only offering patch option for Lodash vulnerability](https://dev-to-uploads.s3.amazonaws.com/i/t446lcruqd3zuyiy2onj.png)

So despite there being a secure Lodash version, Snyk isn't able to suggest it.

This is because currently the Snyk CLI only considers top-level dependencies for upgrades, even if the vulnerability exists in a deeply nested sub-dependency. So if it cannot find a new version of that very top dependency which would elevate the version of the sub-dependency, it will report that there are no fixes available!

Now, this particular example is a little contrived because we manually set the Lodash version to something older - but this can happen all the time in the wild: The current version of a sub-dependency will be found to have a vulnerability by Snyk. Initially there won't be a fix so you might opt to ignore the vulnerability until a fix is released. Sooner or later the sub-dependency will release an official patched version, but because Snyk _only_ considers top-level dependency upgrades, it won't offer you the fix for the sub-dependency - very frustrating!

This is where additional tooling such as [Snyker](https://github.com/asos-craigmorten/snyker) can come in very handy [Disclaimer: I'm the author!].

# Snyker to the rescue

Snyker is an opinionated CLI wrapper around Snyk which helps upgrade these sub-dependencies which Snyk misses. Much like Snyk, it is available through NPM:

```bash
# Start fixing vulnerabilities straight away using NPX
npx snyker

# Add to your global NPM packages
npm i -g snyker

# Or to your global Yarn packages
yarn global add snyker
```

Let's see what it does when faced with our Lodash situation which Snyk isn't managing to upgrade:

```console
$ npx snyker         
[SNYKER: STARTING]
[SNYKER: STEP 1]: Ensuring lockfile 'yarn.lock' is up to date.

yarn install v1.22.4
[1/5] 🔍  Validating package.json...
[2/5] 🔍  Resolving packages...
success Already up-to-date.
✨  Done in 0.24s.

[SNYKER: STEP 2]: Deleting '.snyk' file.
[SNYKER: STEP 3]: Getting vulnerable paths from Snyk.
[SNYKER: STEP 4]: Deleting vulnerable paths from 'yarn.lock' file.
[SNYKER: STEP 5]: Running 'yarn install --force' to force sub-dependency updates.

yarn install v1.22.4
[1/5] 🔍  Validating package.json...
[2/5] 🔍  Resolving packages...
[3/5] 🚚  Fetching packages...
[4/5] 🔗  Linking dependencies...
[5/5] 🔨  Rebuilding all packages...
success Saved lockfile.
✨  Done in 14.75s.

[SNYKER: STEP 6]: Getting remaining vulnerable paths from Snyk.
[SNYKER: COMPLETE]
```

From the output we can see that it has removed vulnerable paths based on results from Snyk and then forced sub-dependencies to upgrade. Let's see if it's fixed our Lodash issue:

```console
$ snyk test --dev

Testing express...

Organization:      ****
Package manager:   yarn
Target file:       yarn.lock
Project name:      express
Open source:       no
Project path:      express
Licenses:          enabled

✓ Tested 314 dependencies for known issues, no vulnerable paths found.
```

:tada: :tada: :tada:

It looks like the Lodash vulnerability has been sorted, and inspecting the `yarn.lock` we can see that it has been upgraded back to the secure version `4.17.19`.

# Takeaways

1. Snyk can be a great tool for finding and fixing vulnerabilities with your node modules, including a useful wizard for interactively upgrading, patching and ignoring vulnerabilities.
1. Snyk struggles with sub-dependencies. So when faced with a nested package with a vulnerability, additional tooling such as [Snyker](https://github.com/asos-craigmorten/snyker) can help you to enhance Snyk to keep your modules vulnerability-free.

---

Hope this was useful folks!

There is _a lot_ more to Snyk that I haven't covered - if you're interested in learning more about the CLI I recommend checking out the [Snyk Cheatsheet](https://snyk.io/blog/snyk-cli-cheat-sheet/). There is also tonnes of information on other parts of Snyk's offering(s) on their [website](https://snyk.io).

What are you using for security scanning? Have you found a clever way to utilize Snyk in your workflow? I'd love to hear all your comments, queries and suggestions so please drop them in the section below!

Till next time y'all! :wave: