iTranslated by AI
Safely Updating Node Packages to Address Vulnerabilities
2022 is almost over.
Is there something you've left undone?
Yes, vulnerability handling. Let's get to it.
Introduction
When searching for how to handle node package vulnerabilities, one common example is checking for vulnerabilities with npm audit and automatically upgrading versions with npm audit fix.
However, you cannot guarantee zero impact on the application; some packages might stop working due to the version upgrade, or warnings might start appearing during the build.
I will describe the procedure for performing version upgrades carefully while investigating dependencies.
This content is a summary of the investigation method rather than just the upgrade process.
Procedure
Basically, you should upgrade the vulnerable package and perform an operation check to see if there are any issues. However, if there are dependencies, you need to investigate whether upgrading the version of the parent package will resolve the issue.
Detecting Vulnerable Packages
Identify vulnerable packages using yarn audit.
$ yarn audit

Vulnerability levels are output in three stages: Critical, High, and Low.
At a minimum, resolve the Critical ones.
You can also display only Critical vulnerabilities using the --level option.
$ yarn audit --level critical
Checking the Dependency List of the Package
Investigate whether the vulnerability can be resolved by upgrading the version of the main parent package in the dependency chain.
$ npm ls {package-name}
In this case, let's look at the dependencies of trim as an example.
$ npm ls trim
└─┬ textlint@11.9.1
└─┬ @textlint/textlint-plugin-markdown@5.3.5
└─┬ @textlint/markdown-to-ast@6.3.5
└─┬ remark-parse@5.0.0
└── trim@0.0.1
We can see that it is being used as a dependency of textlint@11.9.1.
Checking the Latest Version of the Parent Package
Check the latest version of the parent package.
$ yarn info textlint
Output with irrelevant parts omitted:
{
name: 'textlint',
description: 'The pluggable linting tool for text and markdown.',
'dist-tags': {
latest: '12.2.3',
beta: '12.0.0-beta.3',
canary: '10.3.0-alpha.0f2fd6f9',
next: '10.0.0-next.2'
},
dependencies: {
'@textlint/textlint-plugin-markdown': '^12.2.3',
},
}
Since the latest version of textlint is 12.2.3, there is room to upgrade from 11.9.1 -> 12.2.3.
In the dependencies section, we see the @textlint/textlint-plugin-markdown item we confirmed earlier in the dependency chain. By updating textlint to the latest version, this can also be upgraded from 5.3.5 -> 12.2.3.
Investigating Whether the Version Upgrade Resolves the Issue
Let's trace the dependencies and double-check if upgrading textlint to 12.2.3 will also raise the version of trim.
Since textlint@12.2.3 uses @textlint/textlint-plugin-markdown@12.2.3, we will check by specifying the version with yarn info.
$ yarn info @textlint/textlint-plugin-markdown@12.2.3
Result ↓ (irrelevant parts omitted)
{
name: '@textlint/textlint-plugin-markdown',
description: 'Markdown support for textlint.',
'dist-tags': {
latest: '12.2.3',
canary: '4.1.0-alpha.0f2fd6f9',
beta: '12.0.0-beta.3'
},
dependencies: {
'@textlint/markdown-to-ast': '^12.2.3'
},
}
We found that @textlint/markdown-to-ast version 12.2.3 is being used.
We will investigate the dependencies in the same way.
$ yarn info @textlint/markdown-to-ast@12.2.3
Result ↓ (irrelevant parts omitted)
{
name: '@textlint/markdown-to-ast',
description: 'Parse Markdown to AST with location info.',
'dist-tags': {
latest: '12.2.3',
canary: '6.1.0-alpha.0f2fd6f9',
beta: '12.0.0-beta.3'
},
dependencies: {
'remark-parse': '^9.0.0',
},
}
Since remark-parse version 9.0.0 is being used, let's check it.
$ yarn info remark-parse@9.0.0
Result ↓ (irrelevant parts omitted)
{
name: 'remark-parse',
description: 'remark plugin to parse Markdown',
'dist-tags': {
latest: '10.0.1',
next: '9.0.0-alpha.1'
},
dependencies: {
'mdast-util-from-markdown': '^0.8.0'
},
}
Since trim is not used in remark-parse version 9.0.0, we have confirmed that updating textlint to 12.2.3 will resolve the trim vulnerability.
Performing the Version Upgrade
Specify the version you want to upgrade to using yarn upgrade-interactive.
By adding the --latest option, you can also display the latest versions that are not specified in package.json.
$ yarn upgrade-interactive --latest

Select the packages you want to update and execute.
Re-verification After Version Upgrade
Since you have performed the version upgrade, check if the vulnerability has been resolved.
$ npm ls trim
Result
└── (empty)
By upgrading textlint, trim is no longer used in the dependencies.
Running yarn audit again should show fewer vulnerabilities.
$ yarn audit
The vulnerability handling itself is now complete.
Operation Check
Perform operation checks around the features affected by the version upgrade.
Try building with yarn dev and check if any errors occur.
In this case, we updated the major version of textlint from 11.9.1 to 12.2.3.
Because we raised the major version, there is a possibility that sentences which didn't cause linting errors before might now be flagged.
(In fact, when I ran textlint, a few errors appeared, so checking is important.)
Conclusion
We performed version upgrades while tracing dependencies for vulnerability handling.
While it is difficult to investigate each one individually like we did this time, identifying the cause becomes very hard if you update everything at once and get many errors during a build.
If you want to handle vulnerabilities safely and reliably, it's best to do them one by one, and if you can check frequently—about once every three months—it seems you can handle them with low cost.
Discussion