It should, and you should test that it does. In a monorepo the call path from your service to a vulnerable library often runs through an internal package. A tool that analyses each package in isolation can call a finding unreachable when another package in the same repository calls it.
What reachability asks
Reachability analysis asks whether code in your project can actually call the vulnerable function. If no call path exists, the finding is less urgent. If one does, it moves up the queue.
In a single application the path starts at the entry points and follows calls into libraries. In a monorepo there is an extra layer: services call internal libraries, and internal libraries call third party libraries.
Where isolation goes wrong
Take a shared package named utils that wraps an XML parser. Service A calls utils. Service B never does. The vulnerable parser function sits inside utils.
| Analysis scope | Result for utils alone | Result for Service A | Correct? |
|---|---|---|---|
| Package in isolation | No entry point calls it, unreachable | Not analysed | No, Service A reaches it |
| Whole workspace graph | Reachable from Service A | Reachable | Yes |
An isolated scan marks the finding unreachable and the ticket is closed. Service A stays exposed.
The reverse also happens. A library exports twenty functions and only two are used anywhere in the workspace. Analysing it alone treats all twenty as potential entry points and everything looks reachable.
Questions to ask a tool
- Does it build one call graph across workspace packages, or one per package?
- How does it treat the internal workspace links between packages?
- What does it do with dynamic calls, reflection or dependency injection? Those can hide paths.
- Can it show the call path, so a human can check it?
- What does it report when it cannot decide: unreachable, or unknown?
The last question matters most. Unknown should stay visible. See questions to ask a vendor about reachability claims and test a vendor reachability claim.
A simple test you can run
Create a small test in a staging copy of your monorepo. Add a package that calls a known vulnerable function, and a second package that does not. Add a service that depends on the first. Run your scanner. A tool that handles internal boundaries marks the first package reachable through the service and the second not. Delete the test afterwards.
Do not over trust either result
Reachability reduces noise. It does not prove safety. Dynamic code, plugins and configuration driven behaviour can all create paths a static analysis cannot see. Treat unreachable as lower priority, not as fixed, and keep upgrading on a schedule.
Safeguard offers reachability analysis, and you can see how it narrows a list in the demo. Try the free scan at https://gold.safeguard.sh/scan on one project.
Try it yourself
Click through the demo and look at how findings change once call paths are considered.
Click through it at your own pace, or open it full screen.
Quick check
Why can per package reachability give a wrong answer?
The call that reaches the vulnerable function may come from another package in the same repository.
Should unreachable findings be closed?
Lower their priority, but keep them visible, since dynamic behaviour can hide call paths.
Last reviewed: 19 October 2026.