When a critical zero-day drops for a widely deployed library, the response sequence at most organizations goes roughly like this: SCA scanner fires alerts against every service in the dependency graph that imports the affected package, AppSec team starts working through the list, every affected service gets tagged as high priority, and engineering teams get paged with "update this dependency immediately." The process is rational given the information available, and it often results in significant engineering time spent on patches that did not actually reduce exploitability in the production deployment.
The fundamental problem is that "do we use this package?" is not the operational question that matters in the first hour. The operational question is: "does any path from an attacker-accessible entry point in our deployed application reach the specific vulnerable function identified in this CVE?" Depending on the package is a necessary but not sufficient condition for exploitability. The call chain from entry point to vulnerable function has to exist in your specific application for the vulnerability to be reachable.
What the CVE tells you and what it does not
A CVE advisory typically tells you the affected package, the affected version range, the vulnerability class (deserialization, buffer overflow, SQL injection in the library's own query construction, etc.), and the conditions under which the vulnerability can be triggered. What it does not tell you is how your application uses the package, which of your handlers call the affected function, and whether the code path from those handlers can be triggered by attacker-controlled input.
Those application-specific facts are the difference between a vulnerability that is critical for your deployment and one that is present but unexploitable in your specific configuration. A deserialization vulnerability in a parsing library is critical if your application deserializes attacker-supplied data using that library. It is theoretical if your application uses the same library only to deserialize data from a trusted internal configuration file that is never user-influenced.
In a microservice architecture with dozens of services and hundreds of dependencies, determining which services have an actual exploitable path to the vulnerable function requires traversing the call graph of each affected service. Without pre-built graph context, this is hours of manual work per service, compounded across however many services import the affected package.
The first-hour triage sequence with graph context
With a pre-built application graph, the zero-day response sequence changes substantially. Instead of starting from "which services import this package," the analysis starts from "which entry points in any service have a call chain that reaches the vulnerable function in this package." That is a query against the graph, not a manual code review.
The query produces a ranked list: services where the vulnerable function is reachable from an unauthenticated external entry point (immediate action), services where the vulnerable function is reachable from an authenticated entry point (urgent but scope-limited), services where the package is imported but the vulnerable function is not in any call chain reachable from any entry point (schedule for next dependency update cycle), and services where the package is imported but not used in any code path at all (informational, deprioritize).
That ranking tells you where to direct engineering time in the first hour. It does not tell you to ignore the lower-priority categories; it tells you in what order to address them and with what urgency. The services with unauthenticated reachable paths to the vulnerable function need immediate mitigation, whether that is the patch, a WAF rule if the package is available, or temporary disabling of the affected functionality. The services with the package imported but the function unreachable can be patched in the next scheduled release.
Why zero-day response exposes the debt of deferred graph construction
The triage sequence above requires the application graph to exist before the zero-day drops. If the first time you try to construct the call graph is at 2am during an active zero-day response, the graph construction time is part of the incident timeline. For a non-trivial microservice application, building that graph from scratch under pressure, while simultaneously managing stakeholder communication and patch coordination, is not feasible.
This is the strongest argument for maintaining a current application graph as a standing operational artifact rather than treating reachability analysis as something you do ad-hoc. The graph needs to be pre-built, kept current as services change, and queryable at zero-day response time. The investment in building and maintaining the graph pays dividends every time a high-severity CVE drops for a widely-used library, which in practice means multiple times per year for any organization running a dependency-heavy microservice stack.
Transitive dependencies and the depth problem
Zero-day response is harder when the vulnerable package is a transitive dependency rather than a direct dependency. A direct dependency appears in your package manifest and is immediately visible in dependency scanning output. A transitive dependency appears because something else you depend on depends on it, potentially several levels down the dependency tree.
The reachability question for a transitive dependency is the same as for a direct dependency, but the call chain is longer. The entry point calls your handler, which calls a direct dependency, which calls an indirect dependency, which calls the vulnerable function. The traversal depth increases, and the probability of finding such a chain in any given service decreases, but when the chain exists, it is just as exploitable as a direct call to the vulnerable function.
Transitive dependency vulnerabilities are also harder to patch because the fix requires updating the intermediate dependency to a version that itself depends on a fixed version of the affected package, which may not be available immediately after the CVE drops. In that window before a fix is available, the reachability classification tells you whether you have an actively exploitable path that needs a workaround versus a theoretical path that can wait for an upstream fix.
What good zero-day response infrastructure looks like
A team that handles zero-day response well has, at minimum, a dependency inventory that maps which version of each dependency is running in each service in production right now, not in the package manifest but in the actual deployment artifact. They have a call graph that can be queried for a given function and return the set of entry points from which that function is reachable. And they have a deployment topology model that tells them which entry points on which services receive external traffic versus internal-only traffic.
The combination of those three artifacts produces an exploitability verdict within minutes of a CVE disclosure, not hours of manual investigation. That speed difference matters most precisely when the window before active exploitation is measured in hours rather than days.
Not every team has all three of those artifacts today. Building them is not a zero-day response project; it is an ongoing operational investment in application observability that serves multiple use cases beyond incident response. Reachability-informed vulnerability triage, security review of new service deployments, and documentation of attack surface for compliance purposes all benefit from the same underlying graph infrastructure. Zero-day response is just the scenario that makes the cost of not having it most visible.
See reachability analysis on your own code
Connect your repositories and apply a reachability filter to your existing scanner findings. No configuration changes to your current toolchain required.
Request early access