How Agents Transform Reachability in the Software Supply Chain

Published on Sep 23, 2026

Reachability in Supply Chain Risk

Modern applications can include thousands of third-party packages, with most of them being transitive dependencies you never added. Scanners will flag known vulnerabilities throughout that dependency tree. But many of those reports don’t matter to you, because your application code may not even reach the vulnerable function.

AI agents are making this worse by adding code and dependencies faster than teams can review and triage the findings.

Reachability is one of the most useful signals for the vulnerabilities that happen to be present somewhere in the tree from the vulnerabilities your code can actually reach.

It traces calls through your dependencies to see whether your application can reach the vulnerable function:

  1. Read the advisory to find out what you’re looking for: which package, which versions, and which function. The advisory rarely tells you more than that, so you also have to read the vulnerable package itself to understand how the flaw is triggered and which calls lead into it.
  2. If the vulnerable package is transitive, reconstruct the dependency chain and obtain the source for each package along the path. Those intermediate packages form part of the execution path, so their code has to be analyzed as well.
  3. Trace whether an execution path exists from your application’s code to the vulnerable function. If one does, the vulnerability is reachable.

The two shapes a reachability path can take

A repository's source code sits on the left, with four highlighted lines where it calls into a dependency. Two paths lead away from it. The first runs straight down a short channel into a vulnerable package the repository depends on directly: the call chain is one hop, and the package is labelled Direct. The second runs right, through a mesh of middle packages that the repository never added itself, along a much longer channel, and ends at the same vulnerable package, labelled Transitive. Both paths reach the same vulnerable function; the transitive one reaches it through packages that appear nowhere in the repository's own manifest, which is why tracing it needs the source of every package in between.

Source code

example/repo_name

Middle packages

Vulnerable package

Direct

Vulnerable package

Transitive

Where static call graphs fall short

The dominant approach across the market is still static call graph analysis: Map which functions call each other, then check whether a path reaches the vulnerable code. Its speed has made it an industry standard, though it comes with significant blind spots.

Problem 1: Real execution paths are not limited to function calls.

Static call graphs model relationships between functions, but modern applications often cross boundaries that are invisible to that model. Code can be invoked through command-line entry points, event callbacks, dynamically resolved imports, configuration, or other runtime behavior. These patterns are increasingly common in containerized and cloud-native applications.

OWASP NodeGoat is a good example. Its Procfile starts the application through the forever CLI. During startup, forever invokes nconf’s configuration setter, the function affected by CVE-2022-21803.

In our benchmark, our agent reasoned through the deployment command, followed the execution path across the CLI boundary, and traced it all the way to the vulnerable function. Every other product we tested relied on static call-graph analysis and missed the path entirely.

Problem 2: The vulnerable code is not always invoked directly by your application.

Frameworks and middleware rely on inversion of control: your application registers a component once, then the framework decides when to run it. Body parsing middleware is a simple example. You register it with one line at startup, and from then on the framework calls the underlying parser on every request. The vulnerable function is reached during execution, but no explicit call to it appears in the source code, leaving no edge for a static call graph to follow.

Problem 3: Static analysis has to be rebuilt for every language and framework.

Each ecosystem needs its own parser and call graph builder, and those are expensive to write and expensive to keep current, because languages keep adding features and frameworks keep finding new ways to wire code together. It’s worst for dynamically typed languages and for frameworks that lean on reflection or dependency injection, where the real call targets aren’t known until the program runs. When the support for an ecosystem is missing or behind, the scan skips that code and reports the vulnerability as unreachable.

These blind spots are well known. What’s new are how agents can approach the problem more like a team of security researchers: follow a string path to the module it loads, recognize a framework that hooks itself in on import, work through a language the static tooling never caught up with. That’s why agentic reachability is a major focus for us, and why we believe it can materially outperform static analysis.

Agentic reachability scanning at scale

If you naively point an agent at this transitive dependency reachability problem, you hit a scalability wall fast. The combinations of packages and versions form a huge graph, and there’s no way an agent can explore it from scratch on every scan.

At depthfirst, we found that a large share of the subgraphs are duplicates, so exploring them one scan at a time is mostly repeated work. We trace each distinct subgraph once and reuse the result everywhere else, which cuts the search space by about 90%.

depthfirst’s agentic SCA scanning

Knowing a vulnerability is reachable isn’t enough to act on it. We show how your code reaches it: which function in which package calls the next one, all the way down to the vulnerable function. An engineer can read the path and decide for themselves. When the vulnerability is in a direct dependency, we also check whether it’s exploitable in your code, which filters out more noise. And once a finding is worth fixing, our remediation agent can open the upgrade PR for you, so all an engineer has to do is review it.

Conclusion

Traditional static call graphs cover the easy cases. In our agentic approach, an agent reads the code the way an engineer would, so it can follow the invocations a graph misses, in whatever language it finds, across as many packages as the chain runs through. Sharing results across scans keeps that affordable on every scan, and every reachable finding comes with the path that proves it. Add exploitability for direct dependencies, and teams only get a short list of findings worth their time.

Transitive reachability is available now for Depthfirst customers, and runs as part of every SCA scan. If you want to see the reachable paths in your own dependency tree, book a demo below.