Skip to main content
A package can appear in your dependency graph, be imported, and still not be exploitable in practice: the vulnerable function may never be called, or nothing an attacker controls may reach it. Reachability is one of the strongest signals for reducing noise. Combined with advisory severity and the KEV and EPSS exploit signals below, it indicates which findings to prioritize. Reachability analysis goes beyond checking whether a package is imported. For each vulnerable dependency, ZeroPath assesses whether the vulnerable code path is actually invoked from your application, and weighs whether attacker-influenced input can reach it.
Reachability and exploitability are related but distinct. Reachability is whether the vulnerable code is invoked from your code. Exploitability is whether an attacker can trigger it, given inputs, configuration, and trust boundaries. Reachability is a necessary condition for exploitability, not proof of it.

Package reachability

Every vulnerable package receives a reachability status:
  • Reachable — the vulnerable code path is invoked in your application.
  • Not reachable — the package is present but the vulnerable path is not invoked. Dependencies that run only at build or development time are weighted toward this state.
  • Not tested — analysis has not run for this package yet.
A package stays not tested until analysis has run for it; ZeroPath does not assume reachability. Each result includes a short summary, and you can filter the inventory and findings views by package reachability.
A not reachable result lowers priority but is not proof of safety. Static and AI-assisted reachability can miss reflection, dynamic dispatch, deserialization, and configuration-driven invocation. Do not treat “not reachable” as a reason to leave a critical or KEV-listed advisory unpatched.

Exploitability on findings

At the finding level, ZeroPath rolls each finding’s reachability verdict into the exploitability buckets you can filter the findings view by:
  • Likely exploitable — reachable.
  • Needs review — reachability is ambiguous.
  • Likely not exploitable — not reachable.
  • Not yet analyzed — analysis has not completed for this finding.
Findings in the likely-exploitable bucket are the highest priority. Reachable findings can be addressed with auto-remediation, which opens upgrade PRs. The preconditions on a finding indicate what still has to be true for a reachable issue to fire.

Exploit intelligence: KEV and EPSS

Reachability tells you whether a vulnerability is exploitable in your code. Two industry feeds tell you whether it is being exploited in the wild, and ZeroPath enriches every CVE finding with both, refreshed daily:
  • CISA KEV (Known Exploited Vulnerabilities) flags a finding as Known exploited when its CVE is in CISA’s catalog of vulnerabilities under active exploitation, with the date CISA added it and a known-ransomware-campaign flag. An active-exploitation listing is the strongest priority signal for a finding.
  • FIRST EPSS (Exploit Prediction Scoring System) is the probability that a CVE will be exploited in the next 30 days, shown as an EPSS score with its percentile rank, so you can rank not-yet-exploited CVEs by likelihood.
A finding that is reachable, KEV-listed, and high-EPSS is your top priority. A not-reachable finding with a low EPSS score and no KEV listing can usually wait.
If a CVE is not in KEV or EPSS does not score it, no badge is shown. When a feed cannot be reached during a scan, ZeroPath records an Exploit intelligence unavailable coverage warning.

Preconditions

When a vulnerability is reachable but its exploitation depends on conditions that cannot be confirmed from code alone, ZeroPath surfaces preconditions, for example “Vulnerable method is only called with server-controlled input” or “Requires a specific runtime configuration to trigger.” Preconditions let you judge real-world exploitability for each reachable finding.

Transitive triage

Most dependencies are transitive, and investigating every transitive CVE indiscriminately buries the findings that matter. Before spending analysis effort on a transitive vulnerability, ZeroPath evaluates whether the dependency chain actually exposes it. Deep, opaque chains and development-only dependencies are deprioritized, so investigation concentrates where a real, reachable path is plausible.

Dependency graph and scan generations

Each full scan produces its own dependency inventory. When a newer scan supersedes an older one, the older scan’s dependency graph is retired — its edges are removed from the inventory while the vulnerable package record itself is preserved. A finding whose own scan generation was retired therefore has no dependency graph of its own, so ZeroPath reads the dependency path from the current scan of the same branch, as long as that scan still contains the same package (same manifest path, name, version, and ecosystem). Only when no current scan of that branch contains the package does the finding show an empty dependency-path list and no transitive-dependency edges. That is not because the package has no dependencies, but because no stored graph can answer for it. When reading issue details via the API, two fields on the SCA package object say where the path data came from, and exactly one of them is present. dependencyPathsSource is present whenever path data is available: kind: "finding_generation" means it comes from the finding’s own scan generation, and kind: "current_generation" means it comes from the current scan of the finding’s branch, identified by scaScanId. In both cases scaPackageId names the package record whose dependency graph was read. dependencyPathsRetiredAt (an ISO 8601 timestamp) is present instead when the finding’s generation was retired and no current scan of its branch contains the package; the path data is then unavailable. The source also carries isDirectDependency, which says whether that same scan declares the package directly in the manifest. Use it, rather than the package’s chainHash, to tell how the package enters the dependency tree: chainHash describes the finding’s own package record, and a package that was declared directly when the finding was detected may now be reached only through other dependencies. A finding can hold several records: one per dependency path, and records left on a retired scan next to a current one. ZeroPath reads a finding’s reachability verdict, and every filter and count over it, from its records on current scans, and from its retired records only when it has no current one, so a finding never drops out of a list because its own scan was retired. The reachability analyses shown for a finding are every analysis recorded for its advisory, whichever of its records holds them. In the Supply Chain list, a transitive finding whose only records are on a retired scan shows every dependency path to its package in the current scan of the same branch, or says that its scan’s inventory was retired. The finding itself remains actionable regardless of graph retirement: the vulnerable package, its advisory, and the reachability verdict are all preserved.

Threat model & application context

If you have configured a threat model or application context for a repository, reachability analysis and transitive triage incorporate it. Out-of-scope areas, trust-zone boundaries, and assumptions you define factor into reachability verdicts, so dependencies in subtrees you have marked out of scope generate far less noise.
Reachability and exploitability are AI-assisted, probabilistic assessments. Treat them as prioritization signals, and confirm critical supply-chain findings with human review before relying on them to deprioritize a finding or auto-merge a fix.