The hardest findings to triage are the ones that live at the seams between packages. A vulnerable function sits inside a transitive dependency, three hops down the resolution tree. An attacker-reachable call path enters that function from a middleware layer in another package, which was registered by a plugin system in a third package. No single file, and no single package, contains the exploit. Cross-package analysis is the work of stitching those pieces into a coherent reachability verdict, and it is where reachability-grounded tools like Griffin AI diverge most sharply from Mythos-class pure-LLM tools.
Why cross-package analysis is hard
A modern application is a federation of packages. Even a medium-sized Next.js app pulls in hundreds of first-order dependencies, each of which brings dozens of transitive dependencies. Python, Java, and Go applications have similar shapes. Packages communicate via public APIs, plugin interfaces, event buses, dependency injection containers, and framework lifecycle hooks. The calling conventions are heterogeneous; the ownership is fractured; the visibility is restricted by module boundaries that static analysis must respect.
The CVE stream reflects this complexity. CVE-2022-23812 (the node-ipc protestware incident), CVE-2021-44228 (Log4Shell), CVE-2024-3094 (the xz-utils backdoor), and the ongoing series of incidents in event-stream descendants all involved attacker payloads traversing multiple packages before reaching the vulnerable code. A tool that cannot follow calls across package boundaries will miss the reachability verdict on each of these.
Griffin AI's cross-package model
Griffin AI indexes every package the application can load, not just the first-party source. The indexer runs over the installed node_modules, site-packages, vendor directories, Maven caches, and Go module caches, extracting the call graph, the exported API surface, the imports, and the framework registrations for each package. The per-package graphs are joined at their public API boundaries and at the framework-specific hooks they register.
The joined graph is a single, navigable structure. When Griffin traces a path from an HTTP entry point, it crosses package boundaries the same way it crosses function boundaries. The LLM operating on this graph does not have to infer whether a call crosses a package; it is a property of the edge. That property matters because cross-package edges often change the taint characteristics of the flow: a call from your code into a library usually preserves taint, while a call into a sanitization library often neutralizes it.
Griffin's 2026 Q1 benchmark included 127 CVEs whose reachability required at least two package boundary crossings. Griffin correctly classified 89 percent of them. Heuristic SCA tools classified 41 percent. Pure-LLM tools classified 58 percent when given generous context and 34 percent when limited to realistic retrieval budgets.
Mythos-class behavior at package boundaries
Mythos-class pure-LLM tools struggle with package boundaries because their retrieval layer does not know about them structurally. Retrieval treats files as independent units and ranks them by textual relevance to the query. When the query is a CVE or a code pattern, the retrieved files are usually in the first-party code; the transitive dependency files are almost never surfaced, because embeddings do not have a notion of call-graph proximity.
The result is that the LLM sees the first-party side of the boundary and reasons as if the other side were either empty or implemented in whatever way would be most typical. This is the origin of a specific Mythos-class failure pattern, the "library must be doing the right thing" assumption. Given a call to someLib.validate(input), the LLM infers that validate sanitizes the input, because libraries with that name usually do. But the specific library in question might be a renamed wrapper that just returns true, or a partial validator that checks length but not content. Without the code on the other side of the boundary, the LLM cannot tell.
The failure is not the model's fault; it is the architecture's fault. A pure-LLM tool without an explicit cross-package graph is structurally unable to produce grounded cross-package verdicts at scale.
A concrete example
Consider an Express application that uses a community middleware package to normalize incoming request bodies. The middleware calls a utility package for MIME type detection. The MIME detection utility has a ReDoS vulnerability, tracked as CVE-2022-24434, in its regex parser. The attacker payload is a crafted Content-Type header.
The path for Griffin is: Express router → app.use of the middleware → middleware's body handler → utility's MIME detection call → vulnerable regex. Four package boundary crossings. Griffin's graph has all of them. The taint analysis confirms that the Content-Type header reaches the regex unchanged. The finding cites CVE-2022-24434 and names the specific packages involved.
For a Mythos-class tool, retrieval on the Express application returns the router file and maybe the body handler config. The middleware's source is in node_modules; the utility's source is two directories deeper. The LLM sees app.use(bodyHandler) and can speculate that body processing might be vulnerable, but it cannot confirm the path or name the CVE. A security engineer gets a generic warning instead of a precise finding.
The scaling problem
Cross-package analysis scales badly for pure-LLM tools because retrieval scales badly. Every additional package multiplies the search space, and every additional indirect import reduces the probability that retrieval will surface the right file. Griffin's pre-built graph scales linearly with the number of edges, and the LLM's work scales with the size of the path it has to interpret, not with the size of the codebase.
This is why Mythos-class tools tend to demo well on small repos and degrade on enterprise monorepos. The small repo fits in retrieval; the monorepo does not. Griffin's architecture is designed for the monorepo case from the start, which is why large engineering organizations gravitate toward it.
The ownership question
Cross-package findings raise an ownership question that grounded analysis can answer and ungrounded analysis cannot. When Griffin identifies a reachable path that crosses package boundaries, the finding explicitly names the packages involved and the versions in use. A platform team can see whether the fix belongs in first-party code, in a direct dependency, or in a transitive dependency that requires an upgrade of an intermediate package. The VEX statement can be scoped precisely to the affected version range.
With a Mythos-class tool, the ownership question often dissolves into "we think this is a problem somewhere in our dependencies." That is the worst kind of finding to receive; it is a task without an owner.
How Safeguard Helps
Safeguard indexes every package in your project's full transitive closure and stitches them into a single reachability graph. Cross-package paths are first-class entities in the console: the finding view shows the package hops, the versions involved, and the specific edge that crosses each boundary. Remediation suggestions are scoped to the right package, whether that is a first-party file, a direct dependency upgrade, or a transitive pin. If your team has been frustrated by triage tools that can see part of the path but not the whole thing, Safeguard will close that visibility gap.