Appearance
Fix npm Vulnerabilities
Fix npm vulnerabilities through deliberate, minimal changes to package.json.
If specific packages are specified, focus on those. Otherwise, fix all vulnerabilities reported by npm audit.
Principles
- Control — Know what's changing and why. Avoid tools like
npm audit fixthat obscure which changes are made and why. - Minimal intervention — The cleanest fix is the smallest one.
- Fix at the source — Vulnerabilities originate from direct dependencies. Focus fix attempts there first. Use overrides to pin indirect dependency versions only when fixes cannot be applied via changes to direct dependencies.
- Respect the system —
package-lock.jsonis output, not input. Editpackage.json; let npm derive the lockfile. - Preserve stability — The lockfile makes builds reproducible. Never delete it.
Process
1. Identify all vulnerabilities
Run npm audit. For each vulnerability, note:
- The vulnerable package and version
- The fixed version
- The full dependency path back to the direct dependency
2. Ask: do we need these dependencies?
Before fixing, question whether each vulnerable dependency is necessary.
For each direct dependency in the vulnerability paths, ask the user:
- Is this dependency essential to the project?
- Could we remove or replace it?
Some dependencies (like Express) are core and non-negotiable. Others may offer little value and a security issue tips the scales toward removal.
Ask this once, covering all affected dependencies, before proceeding with fixes.
3. Analyze the fix options
For each vulnerability, determine the available fixes before making changes. This is analysis, not trial and error — vulnerability data is deterministic.
Trace the dependency chain:
- Start from the vulnerable package
- Trace upward through its parent packages
- Continue until you reach your direct dependency
- Note each package and version along the way
Check for a direct dependency fix:
- Look up available versions of your direct dependency
- Check which versions pull in a fixed version of the vulnerable package
- If a fixed version exists, this is your preferred fix
If no direct fix exists, analyze override options:
- For each package in the chain between your direct dependency and the vulnerable one, check if a version exists that resolves the vulnerability
- Identify the highest-level package that has a fix available
- This is your override target
4. Apply and verify each fix
For each vulnerability, apply the fix and verify before moving to the next.
If a direct dependency update resolves it:
- Update the version in
package.json - Run
npm install - Run
npm auditto confirm this vulnerability is resolved
If an override is required:
- Add an override for the highest-level package that resolves the issue:
json
{
"overrides": {
"package-to-override": ">=fixed-version"
}
}- Run
npm update <package-to-override>to apply - Run
npm auditto confirm this vulnerability is resolved
Overriding higher in the tree is better because:
- Fewer side effects on unrelated parts of the tree
- More likely to get other fixes and improvements along the way
- Easier to remove later when the direct dependency catches up
5. If no fix is available
If a vulnerability cannot be fixed through version updates or overrides:
- Document the vulnerability and why it can't be fixed
- Assess the actual risk in your specific usage
- Consider alternative packages that provide similar functionality
- Monitor for upstream fixes
6. Multi-branch repos
Not every branch needs the fix. Check which branches use affected dependency versions before applying. Cherry-pick the fix commit to relevant branches.
Do not
- Use
npm audit fix— loses control, can add unwanted direct dependencies - Edit
package-lock.json— it's generated; editpackage.jsoninstead - Delete
package-lock.json— throws away version stability