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.
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.
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.
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.