Safeguard
Application Security

Reachability Analysis as the Missing Piece of SCA

Most SCA-flagged vulnerabilities aren't exploitable. Here's why reachability analysis — not just dependency matching — is what separates real risk from noise, and where Sonatype falls short.

Aman Khan
AppSec Engineer
8 min read

Open a typical SCA dashboard the Monday after a new critical CVE drops and you'll see the same thing: hundreds of flagged dependencies, a handful of "critical" tags, and a security team with no idea which ten of those findings actually matter. Sonatype, Snyk, and the rest of the legacy SCA category built their businesses on one core capability — matching a manifest file against a vulnerability database. That match tells you a vulnerable package is sitting somewhere in your dependency tree. It tells you nothing about whether your application ever calls the vulnerable function, whether that function is reachable from user input, or whether an attacker could ever trigger it in production. That gap — between "vulnerable dependency present" and "vulnerability exploitable" — is exactly what reachability analysis closes, and it's the single biggest reason AppSec teams are drowning in backlogs they can't defend prioritizing.

What Is Reachability Analysis in SCA, and Why Does It Matter Now?

Reachability analysis determines whether the specific vulnerable code path inside a dependency is actually called by your application, rather than just present on disk. It works by building a call graph — starting at your application's entry points (API routes, event handlers, CLI commands) and tracing every function call outward through your first-party code and into your open source dependencies. If the path from an entry point to the vulnerable function exists, the finding is reachable. If it doesn't — because you only import a logging library for one helper function and never touch the module containing CVE-2024-XXXXX — the finding is not exploitable in your context, no matter how "critical" its CVSS score reads.

This matters now because the volume problem has gotten structurally worse, not better. The average enterprise application pulls in somewhere between 150 and 180 open source dependencies, and Sonatype's own State of the Software Supply Chain research has repeatedly shown that 70-90% of the code shipped in a typical application is third-party, not first-party. Every one of those dependencies drags in its own transitive tree. A single package.json can resolve to 800+ transitive packages. Match-based SCA scans all of them against NVD and GHSA and flags anything with a published CVE — which means the noise scales with the size of your dependency tree, not with your actual attack surface.

How Many SCA Findings Are Actually Exploitable?

Most published research converges on a number between 10% and 25% — meaning 75-90% of dependency vulnerabilities flagged by traditional SCA are never actually reachable in the scanning application. Independent studies from reachability-focused vendors and academic security teams analyzing real production codebases have found that once you filter for call-path reachability, the vast majority of "critical" and "high" findings drop off the list entirely — not because the CVE is wrong, but because the vulnerable function is dead code, isolated in a test harness, or behind a code path the application never executes. This isn't a rounding error; it's the difference between a backlog of 400 tickets and a backlog of 40. For a mid-sized AppSec team triaging manually at roughly 15-20 minutes per finding, that gap alone represents 100+ hours of engineering time per major CVE disclosure cycle spent chasing vulnerabilities that were never exploitable in the first place.

Why Do Sonatype and Legacy SCA Tools Miss Reachability?

Legacy SCA tools miss reachability because they were architected around software composition — building a bill of materials (SBOM) and matching it to vulnerability feeds — not around program analysis. Sonatype Lifecycle, built on the Nexus repository model, excels at answering "what's in my dependency tree" and "is this package known-malicious," which made it the category leader for a decade of compliance-driven SCA. But composition analysis is fundamentally static and structural: it reads manifests and lockfiles, not code execution paths. Bolting reachability onto that architecture after the fact is difficult because it requires a completely different technical foundation — full call-graph construction across language boundaries, accurate resolution of dynamic dispatch and reflection, and continuous re-analysis as code changes, not just as dependencies update. Sonatype has begun layering "reachability" messaging into its product marketing since around 2023, but customer reports and third-party benchmarks consistently describe the coverage as shallow — often limited to direct, single-hop calls in a subset of supported languages, rather than full transitive call-graph tracing. The result is a tool built to answer "what do I have" trying to retrofit an answer to "what can actually hurt me," and the seams show in false-negative and false-positive rates alike.

What Does Reachability Analysis Look Like in a Real Vulnerability?

The clearest example is Log4Shell (CVE-2021-44228), disclosed December 9, 2021, which affected Log4j versions 2.0-beta9 through 2.14.1. Match-based SCA correctly flagged every application with any of those Log4j versions on the classpath — which, given Log4j's ubiquity, meant tens of thousands of applications across the industry lit up as critical simultaneously. But exploitation required the vulnerable JndiLookup class to actually be invoked with attacker-controlled input reaching a logged string, typically via JNDI lookup patterns in log messages. Applications that included Log4j only for a narrow, internal logging configuration that never processed untrusted input, or that had already stripped the JNDI lookup class via a hardening step, were not exploitable — but composition-only SCA couldn't tell the difference and treated all of them identically. Teams doing reachability analysis were able to triage in hours which of their hundreds of Log4j instances needed same-day patching versus which could be scheduled into the normal release cycle, without guessing. The same pattern played out again with Text4Shell (CVE-2022-42889) in October 2022 and with the XZ Utils backdoor (CVE-2024-3094) in March 2024, where the exploitable code path required a very specific SSH configuration that most affected systems didn't have.

How Much Time and Cost Does Reachability Analysis Actually Save?

Organizations that adopt reachability-based prioritization typically report cutting actionable, must-fix findings by 80-90% without reducing actual security coverage, because the findings removed were never reachable to begin with. For a security team handling, say, 500 new dependency CVEs a month across a portfolio of services, that's the difference between triaging 500 tickets and triaging 50-75 — the rest get automatically deprioritized or closed with a documented, defensible "not reachable" rationale instead of sitting in a backlog as unaddressed risk. That reclaimed time compounds: fewer emergency patch cycles, fewer cross-team Slack fire drills over CVEs that turn out to be non-issues, and audit evidence that's actually accurate instead of a spreadsheet of severities nobody trusts. It also changes the conversation with engineering teams, who are far more willing to prioritize a patch when security can show the exact call path proving exploitability rather than citing a CVSS score alone.

How Safeguard Helps

Safeguard builds reachability analysis into the core of its software supply chain security platform rather than treating it as a bolt-on report. When Safeguard ingests your SBOM and dependency graph, it also builds a full call graph of your first-party application code and traces every path from your actual entry points — HTTP routes, message consumers, scheduled jobs — through to the vulnerable functions inside your open source dependencies, across multiple language ecosystems and transitive dependency layers. Every finding in the Safeguard dashboard is tagged with its reachability status and, where reachable, the exact call path an attacker would need, so your team can see the evidence instead of taking a severity score on faith.

That reachability data feeds directly into Safeguard's prioritization engine, which combines exploitability, reachability, exposure (is the service internet-facing), and known-exploited status to produce a ranked list your engineers can actually work through — typically a fraction of the raw CVE count a composition-only scanner would surface. Safeguard also re-runs reachability analysis on every code change, not just on a scheduled cadence, so a new commit that suddenly calls a previously-unreachable vulnerable function gets flagged in CI before it merges, closing the gap that lets exploitable code slip through between quarterly scans.

For teams migrating off Sonatype or running SCA tools side by side, Safeguard is designed to ingest existing SBOM and vulnerability data so you don't lose historical findings during a transition, while immediately re-scoring your backlog against actual reachability. Most teams see their "must-fix now" list shrink by an order of magnitude in the first scan, with full call-path evidence attached to every finding that remains — turning SCA from a noisy compliance checkbox into a prioritization tool your engineering org will actually trust and act on.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.