A mid-sized fintech engineering team runs their first full software composition analysis (SCA) scan and gets back 4,300 open vulnerabilities across 62 repositories. Security tells engineering to fix the 380 marked "critical." Engineering pushes back—there's no way to triage that volume before the next release. This scenario plays out at nearly every organization that adopts SCA tooling, and it's the reason reachability analysis application security has become one of the most searched, and most misunderstood, topics in the AppSec world. Reachability analysis doesn't just tell you a vulnerable package is present in your package-lock.json or pom.xml—it tells you whether your application's code actually calls the vulnerable function. Industry data suggests 70-95% of flagged CVEs in a typical dependency tree are never reachable at runtime. This post breaks down how reachability works, how Mend.io implements it, and where the approach still falls short.
What is reachability analysis in application security?
Reachability analysis determines whether a vulnerable function inside a third-party dependency can actually be executed by your application's own code paths. Traditional SCA tools flag a vulnerability the moment a package version matching a CVE shows up in your manifest file—regardless of whether your code ever imports, calls, or transitively touches the vulnerable function. Reachability analysis adds a second layer: it builds a call graph (static analysis) or observes actual execution (dynamic/runtime analysis) to confirm whether the vulnerable code is on a path your application can reach.
A concrete example: CVE-2021-44228 (Log4Shell) affected any application bundling Log4j 2.0-beta9 through 2.14.1. But not every application that pulled in Log4j actually called the JndiLookup class through a logged, attacker-controlled string. Teams running reachability analysis in December 2021 were able to separate the subset of services that needed emergency patching from the much larger set where Log4j was present but its vulnerable lookup path was never invoked—collapsing an all-hands incident into a targeted one for a meaningful share of their estate.
Why do most vulnerability scanners overwhelm teams with noise?
Most scanners overwhelm teams because they match on package version alone, not on code behavior. A standard SCA tool resolves your full dependency tree—direct and transitive—against a vulnerability database like the NVD or OSV, and flags any match. If your application depends on a library that pulls in 40 transitive dependencies, and even one of those has a known CVE, you get a finding, even if that transitive dependency is only used for a build-time tool that never ships to production.
The result is severity inflation. A 2023 Enterprise Strategy Group survey found that AppSec teams triage an average of several hundred new open source vulnerability alerts per month, and most teams report that fewer than 1 in 10 ever get remediated—not because teams are negligent, but because the volume outpaces available engineering hours. When every finding is labeled "critical" based on CVSS score alone, critical stops meaning anything. Reachability analysis is the mechanism that restores the signal: instead of asking "does this CVE exist in my tree," it asks "can an attacker actually trigger this."
How does Mend.io approach reachability analysis?
Mend.io (rebranded from WhiteSource in 2022) approaches reachability primarily through static effective usage analysis layered on top of its existing SCA engine. Mend's reachability feature, expanded significantly through 2023, builds a call graph for supported languages (Java, JavaScript/TypeScript, and later Python) to determine whether application code invokes the vulnerable method identified in a given advisory. It surfaces a binary "reachable" or "unreachable" flag per finding inside the existing Mend SCA dashboard, which customers use to re-sort their backlog.
Mend's implementation is static-only for reachability at the code level, meaning it evaluates call paths without running the application. That approach scales well and doesn't require instrumenting a runtime environment, but it also means Mend can't observe conditions that only appear during execution—things like which code paths actually fire in production traffic, feature flags that gate a vulnerable route, or dependencies loaded conditionally based on environment. Mend has continued to expand language coverage and precision, but as of its current public documentation, deep runtime/dynamic reachability and container-aware runtime context are not core to the product the way static call-graph analysis is.
What are the limitations of SCA-only reachability detection?
The core limitation of SCA-only reachability detection is that static call graphs can't account for what actually happens when code runs. Static analysis has to make conservative assumptions about dynamic language features—reflection in Java, eval-style constructs in JavaScript, dynamic imports in Python—and when it can't resolve a call path with confidence, it typically defaults to marking the finding as reachable to avoid false negatives. That conservatism is safer than the alternative, but it quietly erodes the noise reduction that made reachability valuable in the first place.
There's a second gap: container and infrastructure context. A vulnerability in a base image layer that's never mounted, or a service that's deployed but receives zero external traffic because it sits behind a feature flag at 0% rollout, looks identical to an actively-exploited path in a purely code-level static model. Teams that have only code-level reachability still end up asking a follow-up question manually: is this service even running, is it internet-facing, and does it handle untrusted input? Without runtime and deployment context, reachability answers "can this be called" but not "will an attacker's request ever get here."
How much can reachability analysis reduce vulnerability backlogs?
Reachability analysis can reduce actionable vulnerability backlogs by roughly 70-90% in typical enterprise codebases, based on patterns reported across the industry since reachability features went mainstream in 2022-2023. Take that earlier fintech example: 4,300 open vulnerabilities, 380 marked critical by CVSS alone. After applying reachability analysis, teams commonly find that only 30-60 of those "critical" findings sit on a code path the application can actually execute. That's not a rounding error—it's the difference between a queue engineering can clear in a sprint versus one that gets permanently deprioritized because it's too large to start.
The business case is measurable in engineering hours. If a security engineer spends 20-30 minutes triaging each finding to determine exploitability manually—checking call sites, confirming the function is imported, tracing whether user input reaches it—reducing a 4,300-item backlog to a few hundred confirmed-reachable items saves hundreds of engineer-hours per scan cycle. That's the real ROI reachability analysis application security tooling is sold on, and it's why Gartner and Forrester have both called out reachability as a required, not optional, capability for SCA and ASPM platforms going into 2025 and 2026 vendor evaluations.
What should teams look for in a reachability analysis tool?
Teams should look for a tool that combines static call-graph analysis with runtime and deployment context, not one or the other alone. Static analysis is fast, works pre-deployment in CI, and catches issues before they ship—but it's inherently conservative on dynamic languages. Runtime and deployment signals—actual traffic to a service, whether a container is internet-facing, whether a workload is even running versus dormant in a registry—resolve the ambiguity static analysis can't. A tool that only does one will either flood you with residual noise (static-only, conservative on unknowns) or miss pre-production risk entirely (runtime-only, blind until deployment).
Language and ecosystem coverage matters concretely: a tool that supports reachability for Java and JavaScript but not Go, Python, or Ruby leaves gaps proportional to your actual stack. Integration point matters too—reachability findings that live in a separate dashboard from your existing PR and ticketing workflow get ignored; findings that annotate the pull request or CI check where a dependency was introduced get acted on. Finally, look for transparency in how "unreachable" is determined—a tool that can show you the actual call path (or lack of one) builds the trust needed for a security team to sign off on deprioritizing a CVE, rather than just trusting a black-box label.
How Safeguard Helps
Safeguard was built around the premise that reachability is only useful when it's tied to the full context of where code runs, not just whether it's theoretically callable. Safeguard combines static reachability analysis across your codebase with deployment and runtime signals—container exposure, network ingress, and actual workload activity—so a finding isn't just "reachable in the call graph," it's "reachable, deployed, and internet-facing," or conversely "present but dormant in an image that hasn't shipped in six months."
That combination directly targets the gap in static-only tools like Mend's current reachability model: instead of defaulting to conservative "reachable" labels whenever a dynamic language feature makes the call graph ambiguous, Safeguard cross-references runtime telemetry to confirm or rule out exposure, cutting false positives further without sacrificing recall on real risk. Findings surface directly in the pull request and CI pipeline where the dependency was introduced, with the actual call path shown so security and engineering teams can verify the reachability verdict rather than take it on faith.
For teams evaluating a move from CVSS-only triage—or from a static-only reachability tool—Safeguard's approach is designed to get you from thousands of open findings to the dozens that represent genuine, exploitable risk, with the evidence to back every deprioritization decision. If your team is drowning in an open source vulnerability backlog and needs a prioritization model that reflects how your application actually runs, that's exactly the gap Safeguard closes.