DEV Community

Craig Morten
Craig Morten

Posted on

How to use Snyk for fixing node module vulnerabilities

Snyk 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.

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:

snyk test
Enter fullscreen mode Exit fullscreen mode

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

snyk wizard
Enter fullscreen mode Exit fullscreen mode

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

snyk protect
Enter fullscreen mode Exit fullscreen mode

It's that simple to use - let's try running it against the Express project:

# 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
Enter fullscreen mode Exit fullscreen mode

You should see something like this in your 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.
Enter fullscreen mode Exit fullscreen mode

Awesome! πŸŽ‰ It's good to know that a project as well-used as Express is free from known vulnerabilities πŸ˜‰.

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! πŸ˜‚

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:

$ 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.
Enter fullscreen mode Exit fullscreen mode

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:

snyk wizard --dev
Enter fullscreen mode Exit fullscreen mode

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

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:

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

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

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

Where Snyk falls down

Let's take our newly upgraded Express and manually downgrade one of it's sub-dependencies, namely 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:

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==
Enter fullscreen mode Exit fullscreen mode

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

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"
Enter fullscreen mode Exit fullscreen mode

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:

$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.
Enter fullscreen mode Exit fullscreen mode

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

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

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 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:

# 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
Enter fullscreen mode Exit fullscreen mode

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

$ 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]
Enter fullscreen mode Exit fullscreen mode

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:

$ 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.
Enter fullscreen mode Exit fullscreen mode

πŸŽ‰ πŸŽ‰ πŸŽ‰

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.
  2. Snyk struggles with sub-dependencies. So when faced with a nested package with a vulnerability, additional tooling such as 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. There is also tonnes of information on other parts of Snyk's offering(s) on their website.

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! πŸ‘‹

Top comments (3)

Collapse
 
lirantal profile image
Liran Tal

Well written Craig. Love this new CLI and your way around the issue :)
FYI I added it to github.com/snyk/awesome-snyk-commu... with a bunch of other tooling for CLIs and IDEs which you or others may find useful.

Collapse
 
ameliadvp profile image
amelia@codacy.com

Hey Craig!

Thanks for sharing this! Maybe you can also help with something in regards to eslint security: ESLint has hundreds (maybe even thousands) of plugins and I wanted to understand for security specifically, can you recommend any (besides the ones in OWASP Top 10, or these below:

  • github.com/nodesecurity/eslint-plu...
  • npmjs.com/package/eslint-plugin-an...
  • github.com/ember-cli/eslint-plugin...
  • github.com/mozfreddyb/eslint-plugi...
  • npmjs.com/package/eslint-plugin-xss)?

What other plugins are there for security? Which are the best/most popular? Thank you so much!

Collapse
 
craigmorten profile image
Craig Morten • Edited

Gosh, a really good and tough question! πŸ˜…

Unfortunately I don't have any particular recommendations for eslint specifically. You certainly appear to have a reasonable list there ( P.S. looks like formatting has truncated your links! ).

The only advice I have in this area ( perhaps more of an opinion ) is to make sure you don't rely 100% on static code analysis tools for your security process. In a similar manner to say testing ( though in some schools of thought security concerns come under the testing bracket ) I would try to work with a hollistic view to ensure good coverage - apply static analysis as well as patching ( this is where Snyk comes in for NPM modules in this article, but also machine / container patching ), WAF, programmer education and processes ( training, code reviews etc. ), integration / e2e tests etc. See the OWASP controls site for a great list of controls to consider when working on your security and threat modelling and mitigation.

Static analysis can be great as provides really fast feedback which is ideal for agile working and quick iterations, but sadly suffers from some well documented disadvantages, e.g. this list taken from the OWASP site:

  1. Many types of security vulnerabilities are very difficult to find automatically, such as authentication problems, access control issues, insecure use of cryptography, etc.
  2. The current state of the art only allows such tools to automatically find a relatively small percentage of application security flaws. Tools of this type are getting better, however.
  3. High numbers of false positives.
  4. Frequently can’t find configuration issues, since they are not represented in the code.
  5. Difficult to β€˜prove’ that an identified security issue is an actual vulnerability.

If your focus is on exploring the static code analysis side of things, I would also recommend checking out this OWASP community list of tools which has a great list of free and paid-for tooling.

Apologies for not particularly answering the question ( especially if you know all of the above anyway as well! ) πŸ˜… I guess sadly the reality is that there isn't a simple one solution solves all at the code level yet - it certainly would be amazing if could just install a plugin and 99% of security issues were discovered statically! πŸ€”

As a slightly more related commentary, just take care ( as general practice when picking modules to use in your workflow ) of the health of the modules, e.g. github.com/nodesecurity/eslint-plu... though potentially the most popular module on your list ( by stars and downloads - not always the best metrics but gives an idea, also not sure what all the listed modules are due to the truncation in your post ) also hasn't been maintained since 2019 with several opened and ignored issues and PRs so risks not providing the coverage you may need as Node evolves and potentially breaking if eslint ever does a major bump with breaking changes ( unlikely though ) πŸ™‚