In September 2023, security researchers began tracking active exploitation of Ray, Anyscale's distributed compute framework used to serve and orchestrate LLM workloads at companies including OpenAI and Uber. The campaign, later named ShadowRay, chained an unauthenticated command-injection flaw in Ray's dashboard (cpu_profile endpoint, fixed in Ray 2.8.1) with a disputed authentication gap in the Jobs API (CVE-2023-48022) that Anyscale classified as intended behavior and left unpatched. Oligo Security reported hundreds of compromised Ray clusters exposing AI models, database credentials, and cloud tokens, and a self-propagating GPU-cryptomining variant — ShadowRay 2.0 — surfaced in late 2025, still riding the same unauthenticated endpoint. What made ShadowRay dangerous wasn't just the bug: it was that Ray sits underneath dozens of independently-owned inference and training services, and almost none of the teams running it knew which of their services actually exposed the vulnerable endpoint to the internet. That is a blast-radius problem, and it needs an SBOM-plus-call-graph answer, not a single patch ticket.
What makes AI infrastructure dependencies different from ordinary libraries?
AI infrastructure dependencies — gateways, inference servers, and orchestration frameworks like Ray, vLLM, or LangChain — differ from a typical library because they sit in the request path of every model call, not just in one function's logic. A vulnerable JSON-parsing library might affect one code path in one service. A vulnerable LLM gateway is invoked by every agent, RAG pipeline, and batch job that routes a prompt through it, often across dozens of internal services owned by different teams. CVE-2023-36258 in LangChain's PALChain, a CVSS 9.8 arbitrary code execution bug in its PythonREPL component reachable via exec() calls, illustrates this: LangChain is a transitive dependency embedded inside countless downstream agent frameworks, so the same fix (shipped in 0.0.236, with a bypass closed in a later release after CVE-2023-44467) had to propagate through every application that imported it, not just LangChain itself.
How do you find every service exposed to a vulnerable AI dependency?
You find every exposed service by treating the problem as a graph query, not a grep. Step one is inventory: a Software Bill of Materials (SBOM), ideally in CycloneDX format, that lists every service's direct and transitive dependencies, including the exact resolved version of the gateway, inference server, or orchestration library in question. Step two is traversal: walking the dependency graph from each vulnerable component upward to every consuming service, because a component three or four levels deep in one service's tree is a direct dependency in another. Ray and LangChain are rarely top-level dependencies of the applications that ultimately call them — they're pulled in by an internal "ML platform" wrapper package, which is itself a transitive dependency of ten different product services. Without walking the full graph, teams only find the services where the vulnerable package happens to appear in requirements.txt, not the ones where it arrived three hops downstream through an internal library.
Why isn't dependency inventory alone enough to scope the blast radius?
Dependency inventory alone isn't enough because appearing in a service's dependency tree and being invoked by that service are different facts, and conflating them produces a blast-radius map that is both wrong and useless for prioritization. A service that imports a package containing a vulnerable Ray Jobs API client but never calls the vulnerable method carries materially less risk than one that instantiates a Ray client and exposes its dashboard on a public load balancer. This is where call-graph, or reachability, analysis matters: it answers whether execution can actually reach the vulnerable function or endpoint from each service's entry points, not just whether the package is present. Combining the two — SBOM for "who has it," call graph for "who actually uses the dangerous part" — is what turns a flat list of a hundred affected repositories into a ranked list where three or four services need action this week and the rest can wait for the next patch cycle.
What additional context turns a reachability finding into a priority?
Reachability alone still leaves you guessing about urgency, because a reachable vulnerability in an internal nightly batch job is not the same emergency as the same vulnerability in an internet-facing inference gateway. The additional signals that matter for AI infrastructure specifically are network exposure (is the Ray dashboard or gateway admin port reachable from outside the VPC, as ShadowRay's victims' were), data sensitivity (does the service route customer prompts, embeddings, or fine-tuning data containing PII), and known exploitation status — CISA's Known Exploited Vulnerabilities (KEV) catalog and EPSS exploitation-probability scores both apply directly to infrastructure CVEs like the ones behind ShadowRay. A vulnerable, internet-facing, KEV-listed gateway processing customer data is a P0. The same package sitting unreachable in a decommissioned staging cluster is backlog. Blast-radius mapping only pays off operationally when it feeds directly into that kind of ranked, exposure-aware queue rather than a flat CVE count.
How should teams build this into an ongoing process rather than a one-time audit?
Blast-radius mapping has to run continuously, because AI infrastructure dependency graphs change with every new agent, fine-tune pipeline, or internal wrapper library a team ships, and a one-time audit is stale within weeks. The practical pattern is to generate an SBOM on every build so the dependency inventory is always current, re-run call-graph reachability against the latest CVE and KEV feeds rather than only at scan time, and alert on graph deltas — a newly-added service that pulls in a gateway with an open CVE should surface automatically, not wait for the next quarterly review. Teams should also track AI-specific artifacts (model weight files, inference-serving dependencies, notebooks, prompt templates) alongside code dependencies in the same graph, since inference servers commonly bundle both, and a vulnerability can live in either layer. The goal is a living, queryable map — not a PDF from last quarter's audit — so that the next Ray-style disclosure gets answered in minutes with a list of exposed services, not weeks of manual repository archaeology.
How Safeguard helps
Safeguard builds the graph this framework describes as a connected pipeline rather than a manual exercise. Deep dependency scanning walks resolved dependency trees to 100 levels deep and captures the full root-to-leaf path for every component, so a gateway or orchestration library buried inside an internal wrapper package is still traced back to every consuming service. Reachability analysis layers a static and dynamic call graph on top, classifying each finding as reachable, conditionally reachable, or unreachable, and folds in runtime exposure, data classification, and business criticality to produce a single priority score — the same reachable-plus-exposure-plus-KEV logic that separates an internet-facing gateway incident from a dormant staging finding. Safeguard's AI-BOM extends that same inventory to model weight files, AI SDK imports, and inference-serving dependencies, so AI infrastructure components are tracked in the same queryable graph as the rest of the software supply chain, and a new disclosure like ShadowRay can be answered with a ranked list of affected services instead of a repository-by-repository search.