Featured image of post Fix security vulnerabilities in Yarn

Fix security vulnerabilities in Yarn

Real-world examples of fixing security vulnerabilities in Yarn

Why fix security vulnerabilities?

Security vulnerabilities are a common issue in software development. They can lead to data breaches, unauthorized access, and other security incidents. It is important to fix security vulnerabilities as soon as possible to protect your data and users.

Finding vulnerabilities

Nowadays, it is possible to integrate various vulnerability scanning tools into your CI/CD pipeline. These tools can help you identify security vulnerabilities in your code and dependencies. One such tool is OpenSSF Scorecard, which combines multiple other tools into a single GitHub action. It uses the OSV service to find vulnerabilities affecting your project’s dependencies. OSV (Open Source Vulnerabilities) is a Google-based vulnerability database providing information about open-source projects’ vulnerabilities.

In this article, we will focus on fixing a few recent real-world security vulnerabilities in our yarn.lock dependencies.

score is 3: 6 existing vulnerabilities detected:
Warn: Project is vulnerable to: GHSA-crh6-fp67-6883
Warn: Project is vulnerable to: GHSA-wf5p-g6vw-rhxx
Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw
Warn: Project is vulnerable to: GHSA-566m-qj78-rww5
Warn: Project is vulnerable to: GHSA-7fh5-64p2-3v2j
Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc
Click Remediation section below to solve this issue

Using local tools to find vulnerabilities

In a local environment, we can use OSV-Scanner to find vulnerabilities in our dependencies. Running:

osv-scanner scan --lockfile yarn.lock

It will output the same vulnerabilities mentioned above but with additional details.

╭─────────────────────────────────────┬──────┬───────────┬────────────────┬─────────┬───────────╮
│ OSV URL                             │ CVSS │ ECOSYSTEM │ PACKAGE        │ VERSION │ SOURCE    │
├─────────────────────────────────────┼──────┼───────────┼────────────────┼─────────┼───────────┤
│ https://osv.dev/GHSA-crh6-fp67-6883 │ 9.8  │ npm       │ @xmldom/xmldom │ 0.8.3   │ yarn.lock │
│ https://osv.dev/GHSA-wf5p-g6vw-rhxx │ 6.5  │ npm       │ axios          │ 0.21.4  │ yarn.lock │
│ https://osv.dev/GHSA-p6mc-m468-83gw │ 7.4  │ npm       │ lodash.set     │ 4.3.2   │ yarn.lock │
│ https://osv.dev/GHSA-566m-qj78-rww5 │ 5.3  │ npm       │ postcss        │ 6.0.23  │ yarn.lock │
│ https://osv.dev/GHSA-7fh5-64p2-3v2j │ 5.3  │ npm       │ postcss        │ 6.0.23  │ yarn.lock │
│ https://osv.dev/GHSA-7fh5-64p2-3v2j │ 5.3  │ npm       │ postcss        │ 7.0.39  │ yarn.lock │
│ https://osv.dev/GHSA-7fh5-64p2-3v2j │ 5.3  │ npm       │ postcss        │ 8.4.21  │ yarn.lock │
│ https://osv.dev/GHSA-4wf5-vphf-c2xc │ 7.5  │ npm       │ terser         │ 5.12.1  │ yarn.lock │
╰─────────────────────────────────────┴──────┴───────────┴────────────────┴─────────┴───────────╯

Another way to find these vulnerabilities is by using the built-in yarn audit command.

Waiving vulnerabilities

In some cases, you may decide to waive a vulnerability. This approach means that you examine the vulnerability documentation and acknowledge it but decide not to fix it.

To waive a vulnerability for the OSV flow, you can create an osv-scanner.toml file in the root of your project. For example, to waive the GHSA-crh6-fp67-6883 vulnerability, you can add the following to the osv-scanner.toml file:

[[IgnoredVulns]]
id = "GHSA-crh6-fp67-6883"
reason = "We examined this vulnerability and concluded that it does not affect our project for a very good reason."

In our example, we will not waive any vulnerabilities, but we will fix them by updating the dependencies.

Updating an inner dependency

In our example, we have a vulnerability in the @xmldom/xmldom package. From the vulnerability URL, we know we must update this package to 0.8.4 or later.

Running yarn why @xmldom/xmldom will show that it is an inner dependency of another package:

=> Found "@xmldom/xmldom@0.8.3"
info Reasons this module exists
   - "msw#@mswjs#interceptors" depends on it
   - Hoisted from "msw#@mswjs#interceptors#@xmldom#xmldom"

Looking at yarn.lock shows:

"@xmldom/xmldom@^0.8.3":
  version "0.8.3"
  resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.3.tgz#beaf980612532aa9a3004aff7e428943aeaa0711"
  integrity sha512-Lv2vySXypg4nfa51LY1nU8yDAGo/5YwF+EY/rUZgIbfvwVARcd67ttCM8SMsTeJy51YhHYavEq+FS6R0hW9PFQ==

We see that 0.8.4 will satisfy the dependency requirement of ^0.8.3. We can update the package by deleting the above section from yarn.lock and running yarn install

We will then see the update:

"@xmldom/xmldom@^0.8.3":
  version "0.8.10"
  resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99"
  integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==

Upgrading an inner dependency by overriding the version

Our following vulnerability is in the axios package. We need to update it to 0.28.0 or later. By running yarn why axios we see that this package is part of a deep dependency chain:

=> Found "wait-on#axios@0.21.4"
info This module exists because "@storybook#test-runner#jest-playwright-preset#jest-process-manager#wait-on" depends on it.

The needed version 0.28.0 does not satisfy the ^0.21.4 requirement. We can override the version by adding the following to the package.json file:

"resolutions": {
  "**/wait-on/axios": "^0.28.0"
},

Upgrading the parent dependency

The following vulnerability is in the lodash.set package. The vulnerability URL shows that there is no fix for this vulnerability. We also see at npmjs.com that this package was last updated eight years ago.

We need to update the parent package that uses lodash.set. Running yarn why lodash.set shows:

info Reasons this module exists
   - "nock" depends on it
   - Hoisted from "nock#lodash.set"

We update the parent by running yarn upgrade nock@latest. Luckily, the latest version of nock does not depend on lodash.set, and lodash.set is removed from yarn.lock.

Removing a dependency

Sometimes the best way to fix a vulnerability is to remove the vulnerable dependency. This can be done with the yarn remove <dependency> command. However, this requires code changes. You must find a different library or implement the removed functionality yourself.

Conclusion

We use the above strategies to fix the vulnerabilities in our project.

  • Updating an inner dependency
  • Upgrading an inner dependency by overriding the version
  • Upgrading the parent dependency
  • Removing a dependency

We can now rerun the vulnerability scanner to verify that we fixed the vulnerabilities.

In addition, we must run our unit test and integration test suite to ensure that the updates do not break our application.

Fix security vulnerabilities in Yarn video

Note: If you want to comment on this article, please do so on the YouTube video.