Can LLMs Determine Whether a Vulnerable Dependency Is Actually Reachable?
A dependency scanner says your service includes a vulnerable version of a parsing library. The obvious next question is whether that matters.
Sometimes it plainly does. The library parses user-supplied input on a public endpoint. Other times the package arrived three levels deep through a build plugin and never runs in production. Telling those cases apart is reachability analysis, and it is one of the most useful ways to cut noise in a dependency queue.
Declared, present, reachable
Three different claims get blurred together.
Declared means a manifest or lockfile lists the package. That is what most basic scanners report.
Present means the package actually ships in the deployed artifact. Dev dependencies, test tooling, and build-only plugins are often declared but not present.
Reachable means application code can execute the vulnerable function, with input an attacker can influence. A vulnerability in a library's XML parser doesn't matter much if you only use its date-formatting helpers.
Each step narrows the list. Only the last one approximates real risk, and it is the hardest to establish.
How reachability is normally assessed
Some SCA tools do static call-graph analysis. They map which functions your code calls, follow those calls into dependencies, and check whether any path reaches a function named in the advisory. This works best when advisories identify specific vulnerable symbols, and in languages where call graphs are reasonably tractable.
It has known blind spots: reflection, dynamic imports, dependency injection, plugin systems, serialization frameworks, and configuration-driven behavior. Static analysis can say "no path found" when a path exists at runtime.
Runtime evidence, such as which classes or modules actually load in production, can complement this. It shows what ran, not everything that could run.
Where an LLM helps
Manual reachability work is mostly reading. An engineer opens the advisory, finds the vulnerable function, searches the codebase for uses of the library, follows wrappers, and reads configuration. An LLM with access to the right material can speed up each step.
- Pinning down the vulnerable code. Advisories often describe the bug in prose. A model can read the advisory and the fix commit and identify which functions or code paths changed.
- Finding usage. Given search results across the repository, it can sort out which call sites touch the affected area and which use unrelated parts of the library.
- Following indirection. It can read wrapper modules and configuration files and explain how a request ends up in the dependency.
- Explaining preconditions. Many vulnerabilities need a specific option enabled or a particular input type. A model can check whether the code sets that option.
- Writing it up. It can produce a clear summary of what was checked, what was found, and what remains uncertain.
That turns a long investigation into a review of a well-organized draft.
Where it falls short
The model is reasoning over the text it was given. If the relevant code is generated at build time, lives in another repository, or is selected by runtime configuration it never saw, its conclusion is incomplete. It may sound confident anyway.
It can also misread an advisory, over-trust function names, or miss a call path through reflection. And a prompt-injected comment in a repository could try to steer its conclusion.
None of this makes the model useless. It means its output is an investigation aid, not a verdict.
A sensible way to use it
- Start with tool data. Use SCA results, any call-graph output, and whether the package ships in the deployed artifact.
- Give the model bounded context. Provide the advisory, the fix diff, relevant source files, and configuration.
- Require evidence. Every claim in its summary should point to a file, line, or advisory passage.
- Ask for uncertainty explicitly. Have it list what it couldn't check.
- Have a person decide. An engineer or security reviewer accepts or rejects the "not reachable" conclusion.
- Record it. Store the reasoning as a VEX statement or documented exception, with an expiry.
Don't let "unreachable" become "ignored"
Even a sound reachability conclusion is temporary. Code changes. A new feature might start calling the vulnerable function next month. Reachability exceptions should be re-evaluated when the code changes or on a fixed schedule.
And if the fix is a simple patch-version bump, it is often cheaper to upgrade than to investigate. Reachability analysis earns its keep on the hard cases: major-version upgrades, missing fixes, or large backlogs of transitive findings.
The answer
Can an LLM determine reachability? It can help an engineer get to an answer faster and document it better. It shouldn't decide exploitability alone, because it only sees part of the system and can be wrong in ways that look convincing.