Pick ten findings labeled reachable and ten labeled not reachable, then trace each to the call site in your code. Count how many labels you can confirm. Check the not reachable group most carefully, because a wrong label there hides a real risk.
What a reachability label claims
Reachability analysis asks whether your code can actually call the vulnerable function in a dependency. A finding marked reachable says a call path exists. One marked not reachable says none was found. Used well, this cuts noise, since many vulnerable packages are present but the dangerous function is never called. The idea is explained in static versus dynamic reachability.
The danger is asymmetric. A false reachable label wastes an hour. A false not reachable label can bury an exploitable flaw.
Prepare the sample
Use adjudicated true positives only, because reachability is meaningless for a finding that is not real. Take ten from each label, chosen by a fixed rule, and include a mix of direct and transitive dependencies. If a tool labels fewer than ten findings in a group, take all of them.
If a tool offers no reachability, skip it for this test and note that. Do not penalize it on a feature it does not claim.
The manual trace
For each sampled finding:
- Read the advisory and identify the vulnerable function or entry point, if the advisory names one. Some do not, and the label then rests on the tool's own analysis.
- Search your code for calls to that function, directly or through a wrapper.
- For transitive packages, check whether the intermediate dependency calls it on your behalf.
- Decide whether a path exists from code that runs in production.
- Record agree, disagree or cannot tell.
| Label | Agree | Disagree | Cannot tell |
|---|---|---|---|
| Reachable | count | count | count |
| Not reachable | count | count | count |
What dynamic code does to the result
Reflection, plugin loaders, dependency injection and generated code can all create paths that static analysis does not see. If your code uses them, deliberately include a few such cases. A tool that is honest about these limits, for instance by labeling findings as unknown instead of not reachable, is behaving better than one that guesses.
Also check what the tool says about its own confidence. A label with an explanation, such as the call path, can be verified in minutes. A bare label cannot.
Interpreting the table
- Many disagree in the reachable row: the tool over reports. That is noise, but a safe failure.
- Any disagree in the not reachable row: examine each one. Even one confirmed miss deserves attention, because teams act on that label by deprioritizing.
- Many cannot tell: the tool does not show enough evidence.
Do not turn this into a single accuracy figure. With twenty samples, report the table and a short comment on each disagreement.
Policy implications
Decide before rollout what a not reachable label is allowed to do. Safe uses include lowering priority and moving a finding to a weekly review. Riskier uses include suppressing it entirely. If the hand check shows misses, keep the label as a sorting aid, never as a deletion rule. Related prioritization signals are compared in how to test prioritization signals.
Try it yourself
Click through it at your own pace, or open it full screen. Watch how many findings move out of the main list, then ask how you would verify each one.
Safeguard includes reachability analysis in its scanning, and the free scan at gold.safeguard.sh/scan lets you run the hand check above on your own repository.
Quick check
Is a not reachable finding safe to ignore?
Not automatically. It is lower priority if the label is right, which is why you verify a sample before relying on it.
Can I check reachability without reading code?
Not reliably. Ask a developer who knows the service to do the trace, which also tests how clear the tool's evidence is.
Last reviewed: 19 October 2026.