Your SCA tool just reported 127 vulnerabilities in your application's dependencies. Your security policy says critical and high vulnerabilities must be remediated within 30 days. But you know from experience that most of those vulnerabilities are in code paths your application never touches.
The question is: which ones?
Reachability analysis answers that question. Safeguard's reachability engine traces the call graph from your application code into your dependencies to determine which vulnerable functions are actually invoked. The result is a dramatically shorter list of vulnerabilities that actually matter.
The False Positive Problem in SCA
Traditional SCA works by matching component versions against vulnerability databases. If your application includes Jackson-databind 2.15.2, and a CVE affects Jackson-databind versions below 2.15.3, you get an alert. The alert is technically accurate: you have a vulnerable version of the library.
But here is the nuance that SCA misses: the CVE might affect a specific function in Jackson-databind that your application never calls. If the vulnerability is in the polymorphic deserialization feature and your application only uses basic JSON serialization, the vulnerability exists in your dependency tree but is not exploitable through your application.
Industry data suggests that 70 to 85 percent of vulnerabilities reported by SCA tools are not reachable in the context of the specific application. That means your developers are spending the majority of their remediation effort on vulnerabilities that pose no actual risk.
This is not just an efficiency problem. Alert fatigue from unreachable vulnerabilities leads teams to deprioritize all vulnerability findings, including the genuinely critical ones. When everything is urgent, nothing is.
How Reachability Analysis Works
Safeguard's reachability analysis combines static call graph analysis with vulnerability-specific function mapping.
Step 1: Vulnerability Function Mapping
For each CVE, we maintain a mapping to the specific functions, methods, or code patterns that are affected. This is the most labor-intensive part of reachability analysis, and it is where the accuracy lives.
Our security research team analyzes CVE advisories, patches, and proof-of-concept exploits to identify exactly which code paths trigger the vulnerability. For CVE-2022-42003 in Jackson-databind, for example, the vulnerable function is ObjectMapper.readValue() when used with UNWRAP_SINGLE_VALUE_ARRAYS feature enabled and PolymorphicTypeValidator not configured. We capture that level of specificity.
We currently maintain function mappings for vulnerabilities in the most widely used open-source libraries across Java, JavaScript, Python, Go, and .NET ecosystems. Coverage expands continuously as our team processes new CVEs.
Step 2: Call Graph Construction
When you enable reachability analysis for a project, Safeguard constructs a call graph from your application's entry points into its dependencies. The call graph traces which functions call which other functions, building a map of all code paths that are reachable from your application's execution.
The analysis uses static techniques -- it analyzes code structure without executing the application. This means it works on source code and compiled artifacts without requiring a running environment.
For each supported language ecosystem, we use the appropriate analysis technique:
- Java -- Bytecode analysis of compiled classes and JARs, resolving method invocations across class hierarchies
- JavaScript/TypeScript -- AST-based analysis of import and require statements, function calls, and module resolution
- Python -- AST-based analysis of import statements and function invocations, with type inference for dynamic dispatch
- Go -- Static analysis of the compiled binary or source, leveraging Go's explicit dependency graph
Step 3: Reachability Determination
With the call graph and the vulnerability function mappings, the reachability engine determines whether any path exists from your application code to the vulnerable function.
The result for each vulnerability is one of three verdicts:
- Reachable -- A code path exists from your application to the vulnerable function. This vulnerability is exploitable and should be prioritized.
- Not reachable -- No code path exists from your application to the vulnerable function. The vulnerability exists in your dependency tree but cannot be exploited through your application.
- Undetermined -- The analysis could not conclusively determine reachability, typically due to dynamic dispatch, reflection, or code patterns that static analysis cannot fully resolve.
"Undetermined" is an important category. We do not mark a vulnerability as "not reachable" unless we are confident in that assessment. When in doubt, we err on the side of caution and mark it undetermined, which is treated as potentially reachable for policy purposes.
The Impact on Prioritization
In practice, reachability analysis reduces the actionable vulnerability count by 60 to 80 percent for most applications. A project with 127 SCA findings might have 20 to 30 reachable vulnerabilities.
That reduction transforms the remediation workflow. Instead of a backlog that grows faster than you can work through it, you have a focused list that a team can address in a sprint. The critical and high-severity reachable vulnerabilities get immediate attention. The unreachable ones are documented (for compliance) but deprioritized.
Safeguard's policy engine integrates reachability into policy evaluation. You can configure policies that:
- Block releases only for reachable critical vulnerabilities (not all critical vulnerabilities)
- Require VEX statements for unreachable vulnerabilities (documenting the assessment)
- Set different remediation SLAs for reachable vs. unreachable findings
This gives you a policy framework that is both strict (genuinely exploitable vulnerabilities are blocked) and practical (non-exploitable vulnerabilities do not block releases).
Limitations and Honesty
Reachability analysis is powerful but not perfect. Here is what it does not do:
Dynamic code paths. If your application uses reflection, dynamic proxies, or plugin architectures to invoke dependency code, static analysis may not detect those paths. We flag known dynamic invocation patterns as "undetermined" rather than "not reachable."
Configuration-dependent reachability. Some vulnerabilities are only exploitable under specific configurations. If a vulnerability requires a feature flag to be enabled, and your application has it disabled, the vulnerability is not exploitable. But static analysis sees the code path as reachable because the conditional branch exists. We address some configuration-dependent cases but not all.
Runtime environment factors. Vulnerabilities that depend on specific JVM versions, operating system features, or network configurations are outside the scope of static reachability analysis.
Coverage gaps. Our vulnerability function mappings do not cover every CVE in every library. For CVEs without function mappings, reachability defaults to "undetermined." Coverage is highest for the most widely used libraries and for critical-severity CVEs.
We are transparent about these limitations because overconfidence in reachability results is dangerous. Reachability analysis is a prioritization tool, not a guarantee of safety. It dramatically improves signal-to-noise ratio, but it does not replace the need for vulnerability management.
Getting Started
Reachability analysis is available on Safeguard's Professional and Enterprise plans. Enable it at the project level, point it at your source code repository (or compiled artifacts for Java), and the analysis runs automatically during SBOM processing.
Results appear in your vulnerability views with a "Reachable" / "Not Reachable" / "Undetermined" badge alongside each finding. Policies can be updated to incorporate reachability status.
The first analysis run takes a few minutes depending on project size. Subsequent runs are incremental and complete in seconds as only changed code paths are re-analyzed.
Start with a project that has a large vulnerability backlog. The reduction in actionable findings is immediately visible and usually dramatic.