Guide 134 workflow

How to handle a transitive dependency vulnerability

Handle a transitive vulnerability across every parent dependency, assess temporary overrides, verify business compatibility, and close against deployed artifacts.

A transitive vulnerability is in a package your application gets through another dependency. Confirm the advisory matches each resolved version, find every parent that introduces it, and choose a repair for each path. Prefer a safe parent update. If a parent has no fixed release, a temporary, reviewed override may work when your package manager supports it and the replacement is compatible. Check the resolved tree, the application behavior, the built artifact and the rollout before calling the work complete. Updating one parent can leave another affected copy behind.

The answer changes when the warning is for a malicious package rather than a conventional vulnerability. A possibly malicious package calls for containment and incident scoping before routine update work. It also changes when the package was installed only in a build job: the affected asset may be CI rather than the running service.

Trace all parents, not just the first one

Illustrative case, with invented packages, versions and advisory: Northstar Support has a Node.js search API and a scheduled reporting worker. Its root package manifest directly lists @northstar-demo/search-ui 4.6.0 and @northstar-demo/report-worker 3.2.0. Its lockfile contains two copies of @northstar-demo/query-parser: version 2.4.1 under search UI and 2.3.9 under report worker. A fictional DEMO-ADV-04 says versions before 2.4.3 may consume excessive CPU when recursive parsing receives deeply nested input. Both copies fall in the invented affected range, even though the developer did not list the parser as a direct dependency.

The first engineering question is “why is each copy installed?” npm's npm explain prints the chain of dependencies causing a package to be installed in the current project. Inspect its output and the committed package-lock.json, including the path and version of each copy. In a monorepo, check the relevant workspace and its release process. A package-name-only search could hide the older worker copy after the search UI is fixed.

Next read the advisory condition, not just its score. The OSV schema records affected ecosystems, packages and versions or ranges. Confirm both matches are for the npm package, not a similarly named project elsewhere. Trace where the parser is used: Northstar's search API receives customer queries, while report worker receives queued report filters. Their inputs, rate limits and process isolation may differ, so exposure is a separate question for each path. If invocation remains uncertain, keep exploitability under investigation while preparing a low-risk update.

Update the parent that has a safe release

Suppose search-ui 4.6.1 changes its parser dependency to 2.4.3. Review that release's provenance and change notes, update the direct parent in a branch, and regenerate the lockfile with the project's normal package-manager settings. The resulting tree now has one fixed copy under search UI and one affected 2.3.9 copy under report worker. That is partial remediation, not closure of the advisory for Northstar.

The update may change more than one package. Inspect the lockfile diff for new dependencies, removed integrity entries, unexpected registry URLs and unrelated major upgrades. A lockfile may flag installation scripts without containing their code; inspect the changed package manifests and script contents through a trusted artifact-review process when installation behavior changes. The npm lockfile documentation explains that it records the resolved tree; that makes it a review artifact, not disposable generated noise. Check all dependency paths again after resolution, because hoisting or deduplication can change which copy a parent uses.

Validate the search API in the team's authorized development or CI environment. An ordinary query should still work; a controlled deeply nested query should meet an agreed resource bound or be rejected. The test fixture, timeout and result belong in the PR. This is normal validation of Northstar's own project, not a suggestion to execute untrusted customer repositories inside a security scanner. A local result does not establish that the fixed artifact has reached production.

Treat the remaining path as an explicit decision

Suppose report-worker 3.2.0 declares the parser range ~2.3.0 and no fixed parent release exists. A direct bump of search-ui cannot change that edge. npm supports root-level overrides that can replace a transitive resolution under a named parent. An illustrative, narrow policy is:

{
  "overrides": {
    "@northstar-demo/report-worker@3.2.0": {
      "@northstar-demo/query-parser": "2.4.3"
    }
  }
}

This forces a version outside the worker's declared ~2.3.0 range. It is not automatically safe: the worker may depend on behavior that changed between 2.3 and 2.4. npm considers overrides only in the root package.json, not in installed dependencies. Regenerate the lockfile, confirm that the worker's affected copy was actually replaced, and inspect what else changed. If the resolver rejects the change or a behavioral check fails, do not relabel the issue fixed. Consider disabling the affected worker feature, restricting its inputs, replacing the parent, or using a reviewed backport until upstream publishes a compatible release.

Let a failed compatibility check change the plan

For Northstar, the override resolves correctly but changes a behavior the worker depends on. In this synthetic compatibility record, parser 2.3.9 returns a date-filter node as Range(start,end), while 2.4.3 returns Comparison(gte,start) and Comparison(lt,end). The worker's adapter only recognizes Range. It treats the new shape as no filter, which would broaden a scheduled report. These invented APIs illustrate why “install succeeded” is a poor compatibility conclusion.

Fixture input Old accepted behavior Override behavior before adaptation Decision
Report for one calendar month Only that month's records Unrecognized node drops date predicate Hold worker release
Ordinary search text Expected bounded results Same expected results API parent update may proceed
Excessively nested filter Must fail within chosen resource bound New parser rejects it under the proposed fixture Useful security evidence, insufficient for worker compatibility

The worker owner changes the adapter to handle the new supported node form and reject unknown forms rather than silently remove a filter. The acceptance record must now contain the resulting predicate or selected synthetic record IDs, not merely “report generated.” A report with too many rows can look like a successful run.

Until that adaptation is validated, the PR should split its decisions:

API change: search-ui 4.6.1 resolves parser 2.4.3; proposed for merge under the normal review policy. Worker change: root override resolves 2.4.3 but the legacy filter adapter drops its date predicate; release held. Next work: adapt the parser contract, compare selected records for ordinary date filters, and check bounded failure for pathological filters. Remaining exposure: worker still contains 2.3.9; temporary controls and expiry recorded separately.

After adaptation, attach the before/after resolved paths and compatibility record to the worker PR. Do not describe the invented results here as executed evidence. npm's npm ci helps reproduce a lockfile-consistent install; it cannot decide whether a changed syntax tree still means the same business filter.

The override remains temporary even if the adaptation works. Its owner watches the upstream parent release, removes the override when the supported path is available, and checks resolution again. A future parent update can otherwise leave an obsolete root override silently pinning the parser.

Close against the affected environments

After merge, check three layers for both parents:

  1. Resolved tree: the target branch and lockfile no longer resolve an affected version through search UI or report worker; other paths were checked or listed as out of scope.
  2. Built artifacts: the API and worker images generated from that revision contain the fixed version or no longer contain the parser.
  3. Running workloads: the new images are deployed to the environments in the issue, including old replicas, scheduled jobs and regions.

A dependency scanner going quiet is useful but insufficient if it changed scope, lost an identity, or scanned a different revision. Likewise, the package's absence from a runtime image does not settle a separate build-time exposure. NIST's Secure Software Development Framework treats remediation and verification as managed development work; preserve what was checked and what remains open.

If the worker override cannot be validated safely this sprint, ship the search UI fix as partial work and open a dated exception or separate worker ticket with its affected artifact, exposure assessment, temporary control, owner, next review and expiry. Do not describe the entire advisory as resolved just because one dependency path is clean.

Northstar's worker repair changes both dependency resolution and the interpretation of report filters. Those contracts deserve separate review questions. The dependency reviewer checks that every identified parent resolves a version outside the fictional affected range. The worker reviewer checks that the chosen parser output still represents the requested report and that unfamiliar output stops processing instead of widening the selection.

Use a small, explicit set of business cases for that second review. The month boundary should retain its intended inclusion rules; an empty result should remain an empty result; and an unsupported expression should produce the agreed failure. The exact fixtures depend on the application's existing semantics. Inventing a new interpretation while repairing the package would hide a product change inside a security update.

A result such as “the worker completed successfully” is particularly weak here. The defect in the synthetic adaptation produces a plausible report with the wrong records. Ask for evidence at the selection boundary: which records the filter admits, which it excludes, and what happens when the adapter cannot represent the expression. Keep sensitive production records out of the review packet; representative synthetic records can demonstrate the intended contract in the team's authorized validation environment.

Plan the temporary override's removal before accepting it

The exception should identify why the override exists, which parent and version it targets, who owns the adaptation, and what event will trigger its removal. “Remove when upstream fixes it” needs an owner who will actually assess the next relevant parent release. A review date keeps the work visible even if that release is delayed.

When a supported parent becomes available, compare the newly resolved graph with the override in place and with the proposed supported path. The goal is not merely to delete the configuration entry. The resulting worker must retain the fixed parser and the intended filter behavior. If the parent now supplies its own compatible adaptation, determine whether Northstar's temporary adapter is still needed before keeping two layers of translation indefinitely.

Also keep rollback deliberate. Reverting the entire lockfile or worker change could restore the affected parser; reverting only the adapter could leave the new parser producing unrecognized nodes. The release owner needs a reviewed fallback that accounts for both parts, which may mean temporarily disabling the report feature while a compatible artifact is prepared. Describe that choice in terms of service behavior and remaining exposure rather than treating any previously working build as automatically suitable.

Next action: for one transitive alert, attach the full dependency chain and before/after lockfile diff to a PR. If you are unsure which affected copy runs in production, start with the deployment check. If you must choose among several repairs, use the prioritization guide.