How it works

Seven steps from a lockfile to a decision. Each one writes down what it found, so the decision at the end can be read backwards.

The pipeline

From the lockfile to the decision

  • Inventory. Every component in package-lock.json, with its development, direct and transitive flags.
  • Advisories. OSV for the advisories themselves, FIRST EPSS for the probability of exploitation in the next thirty days, and the CISA KEV catalogue for exploitation already seen in the wild. All of it cached in a local SQLite file.
  • Code. A call graph of your source using the TypeScript compiler parser, Express routes as entry points with their mount prefixes and authentication guards, and a hint for where request data enters a chain.
  • Reachability. One of six tiers per advisory, each carrying a confidence level.
  • Exposure. Whether a Dockerfile exposes a port, whether compose publishes one, and whether the application binds only to loopback.
  • Decision. An SSVC-style call, a score from 0 to 100 for ordering, and the reasons in plain English.
  • Output. A table in the terminal, a full JSON report, and an OpenVEX document.

Tiers

What reachable means here

TierMeaningDefault
dev-onlyA development dependency, so it is not in the shipped artifact.Set aside
unusedInstalled, but no source file imports it.Set aside
imported-not-calledImported, but none of the vulnerable functions are called.Set aside
imported-unknown-symbolImported, and NextFix has no function-level data for this advisory yet.Watch
called-unreachedThe vulnerable function is called, but no HTTP entry point leads there.Watch
reachableAn entry point leads to the vulnerable call.Fix next cycle

Confidence

A tier is only as good as the data behind it, so every tier is shown with one of three confidence levels.

  • Confirmed. The vulnerable functions for that advisory were curated by hand.
  • Derived. The functions were extracted from the advisory fix commit and reviewed by a person. This is the next piece of work.
  • Package-level. There is no function-level data, so the answer stops at whether the package is loaded.

Grading

What turns reachable into fix now

Reaching the vulnerable call is the start of the question. A finding is then weighed on who can get to the entry point and what the outside world is doing with the advisory.

  • Authentication. An entry point with no guard counts for more than one behind a login.
  • Request data. Whether user-controlled input travels down the chain into the vulnerable call.
  • Exposure. Whether the service is published on a port rather than bound to loopback.
  • Exploitation. The EPSS score and percentile, and whether the CVE is in the CISA KEV catalogue.
  • Severity. The CVSS vector, which contributes rather than decides.

Output

The same answer in a terminal

The dashboards are the comfortable way in, and everything behind them is available from the command line for a pipeline to call.

NextFix 0.3.0 — express-shop 1.0.0
53 components, 20 advisories → 20 findings
Act 1 · Attend 3 · Track* 2 · Track 14
80% of findings need no action right now, with evidence.
Entry points: 4 (3 unauthenticated) · network: published on 3000

DECISION  SCORE  PACKAGE          ADVISORY        REACH              ENTRY          FIX
Act       81     lodash@4.17.15   CVE-2021-23337  reachable          POST /preview  → 4.17.21
Attend    66     express@4.17.1   CVE-2024-29041  reachable          GET /go        → 4.19.2
Track*    42     lodash@4.17.15   CVE-2020-8203   called, unreached                 → 4.17.19
Track     10     moment@2.29.1    CVE-2022-24785  not imported                      → 2.29.2
Track     6      minimist@1.2.5   CVE-2021-44906  dev only                          → 1.2.6

Output from the sample application that ships with NextFix, shortened to fit. The JSON report and the OpenVEX document carry the same findings in full.

Limits

What it cannot tell you yet

Reachability analysis is a claim about your code, so it is worth being exact about where the claim stops.

  • One ecosystem so far. Node.js projects with an npm lockfile. Python and Go are on the roadmap.
  • Express entry points. Other frameworks are recognised as code but their routes are not yet read as entry points.
  • Function data is thin. A curated seed covers a handful of advisories. Everything else is answered at package level, and NextFix says so rather than guessing.
  • The taint hint is a heuristic. It follows request data one level deep along a chain, which is useful for ranking and is not a proof.
  • Dynamic loading is invisible. A call reached only through a computed require or a runtime plugin will not appear in the graph.

A finding that NextFix sets aside is a judgement backed by stated evidence, and you can overrule it. The evidence is there so that you can check the reasoning rather than take the verdict on faith.