How to use Snyk for fixing node module vulnerabilities
Craig Morten
Posted on July 12, 2020
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
Use the guided wizard to ignore, patch or upgrade vulnerable packages:
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:
snyk protect
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
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.
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.
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
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:
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: {}
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
:
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==
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"
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.
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...?
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!
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
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]
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.
π π π
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
- 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.
- 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! π
Posted on July 12, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.