A modern application can carry 500 or more transitive dependencies, and as an Endor Labs technical staffer told Dark Reading, only 10-20% of imported code is typically used by any given application. Standard software composition analysis (SCA) doesn't know this: it matches a manifest against a CVE database and flags every vulnerable package version present, whether or not your code ever calls the vulnerable function. Snyk's own reachability research reports that reachable findings — ones tied to a real, invokable call path — typically make up only 10-30% of everything an SCA scan flags, meaning 70-90% of a typical patch backlog is theoretical risk, not actionable risk. That gap is why security teams drown in open tickets while attackers exploit a much smaller set of actually-reachable bugs. Reachability analysis closes it by building a call graph from your entry points down through every dependency and asking one concrete question: is there a path from code you run to the specific vulnerable sink? This post walks through how that analysis works, what it changes about triage, and — just as important — where it still can't be trusted to make the call alone.
What does reachability analysis actually check?
Reachability analysis checks whether a real execution path exists from your application's entry points to the specific function a CVE affects, not just whether the vulnerable package is installed. It typically works two ways: static reachability parses source, bytecode, or a lockfile to construct a call graph and trace whether any path reaches the vulnerable line, while dynamic reachability instruments a running workload to record which modules and functions are actually loaded and invoked in production. Static analysis catches paths that exist in code but haven't fired yet; dynamic analysis confirms what's genuinely exercised at runtime, including code loaded conditionally through configuration. A finding is then classified along a spectrum — reachable, conditionally reachable (the path exists but sits behind a disabled flag or route), or unreachable (no path exists at all) — rather than the binary "present/absent" result a manifest-matching SCA scan produces.
How much noise does reachability actually remove?
Reachability removes a majority of open findings in most codebases, based on figures multiple vendors report independently. Snyk's published reachability research puts the reachable share of total findings at roughly 10-30% across the codebases it analyzed, meaning 70-90% of flagged CVEs in a typical dependency tree are not invoked by the calling application. Endor Labs has gone further in specific customer analyses, publicly stating it has classified as much as 97% of findings in some codebases as unreachable — a vendor-reported figure, not an independently audited one, but directionally consistent with Snyk's numbers. Dark Reading's coverage of the reachability trend has framed the technique the same way both vendors do: as a triage layer that reprioritizes a backlog, not a tool that deletes vulnerabilities. Practically, this is the difference between a team staring at 400 open CVE tickets and one working from the 40-80 that sit on a path their code can actually execute.
Why can't a package-version match alone tell you what's exploitable?
A package-version match can't tell you what's exploitable because CVE severity is scored against the vulnerability in isolation, not against how a specific application uses the library. A CVSS 9.8 deserialization flaw in a logging or templating library is only as dangerous as the number of ways your code lets untrusted input reach the vulnerable function — if your application never calls the affected method, or only calls it with hardcoded, non-attacker-controlled arguments, the practical risk is close to zero regardless of the CVSS score. This is exactly the gap that made CVE-driven backlogs so unmanageable in the first place: a security team following pure CVSS or "present in manifest" ranking ends up patching the same volume of tickets whether the underlying code is invoked once, one million times, or never. Reachability adds the missing variable — actual invocation — that CVSS was never designed to measure.
Where does reachability analysis fail or get it wrong?
Reachability analysis fails, or at best returns "unknown," anywhere a static call graph can't be built with confidence — dynamic dispatch, reflection, eval-driven execution, deserialization gadgets, and native code all break the assumption that call targets are resolvable ahead of time. Data-driven vulnerabilities are a related blind spot: a path a static analyzer marks unreachable can still be triggered if malicious input reaches it through a route the analyzer didn't model, such as a deserialization payload crafted to invoke a method indirectly. The honest, industry-consistent response to both problems is conservative defaulting: mark ambiguous cases as unknown and keep surfacing them rather than silently suppressing them, and lean on complementary signals — CISA's Known Exploited Vulnerabilities (KEV) list and EPSS exploit-probability scores — for anything reachability can't confidently classify. Vendors and outlets covering this space, including Dark Reading's reporting on reachability tooling, are consistent on this point: reachability narrows a backlog, it does not replace patching discipline for findings it can't confidently rule out.
How Safeguard Helps
Safeguard's prioritization engine treats reachability as one of four signals feeding a single Priority Score, alongside exploitability (EPSS and CISA KEV), runtime context (environment, internet exposure, data sensitivity), and business context (regulatory scope, revenue criticality). It runs static reachability against source, lockfiles, and bytecode; dynamic reachability against live workloads to flag never-executed paths as cold; and configuration reachability to check whether code is even wired into a route or bean definition. Consistent with the industry-wide caveat above, Safeguard classifies dynamic-dispatch and reflection cases as unknown rather than auto-suppressing them, keeping them in front of reviewers. Across aggregate customer tenant data, this combined approach has shrunk open "urgent" queues by 60-80%, turning a weekly backlog of 200-500 CVEs into one closer to 20-60 — figures Safeguard reports as an internal aggregate rather than a third-party-audited benchmark. Griffin, Safeguard's AI layer, can then explain why a given finding was deprioritized and propose a minimum-risk upgrade for the ones that remain.