Handle vulnerabilities

Patch transitive dependencies

Update the nearest responsible parent, use safe overrides temporarily, test behavior, and remove workaround pins when upstream releases a fix.

A vulnerable package may not appear in your manifest. Find which direct dependency introduced it.

npm explain qs
# [email protected]
#   qs@"6.10.3" from [email protected]
#     body-parser@"1.20.0" from [email protected]

You never installed qs, but express did, through body-parser. That chain tells you who is responsible for the fix.

Prefer the parent update

The cleanest fix is updating the nearest responsible parent so the graph resolves naturally:

npm update express
npm audit
# found 0 vulnerabilities

The framework’s maintainers already tested their code against the newer qs. You inherit a combination that upstream actually supports. npm audit fix automates this for semver-compatible updates; treat npm audit fix --force with suspicion, because it will install breaking major versions to silence findings.

Overrides are a temporary tool

Sometimes the parent has no fixed release yet. npm lets you force a version anyway:

{
  "overrides": {
    "qs": "6.11.2"
  }
}

This works, and it is also how you break things. A vulnerable parser arrives through a web framework. Forcing a newer parser with an override removes the scanner warning but breaks an internal API the framework still expects. The override silenced the scanner while creating a runtime bug.

If an override is compatible and urgent, use it — with compatibility tests, a recorded owner and reason, and an expiry condition: “remove when express ships a release depending on qs >= 6.11”. Forking the dependency creates a permanent maintenance obligation and should be a deliberate last resort.

Automate the routine updates

Most transitive fixes arrive through ordinary parent updates. Dependabot (or Renovate) turns them into reviewable pull requests:

version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"

Small weekly bumps keep you close to upstream, so an urgent security update is a patch-level hop instead of a three-major-version migration.

Trace one transitive dependency to every direct parent and save the dependency paths. Apply the smallest supported parent update and run the relevant behavior tests. If you trial an override, add an incompatible-version failure test and record its owner, reason, and removal date.

Lesson completed

Take this course offline

Get every free book, course edition, and software download.

Get the download library →