Pick up any vulnerability report and you will find a flat list: forty-three findings, sorted by severity, each describing one weakness in one place. A reflected XSS on the marketing site. A server-side request forgery on an internal API. An IAM role that can assume a more powerful role. Each is real. Each is graded. And graded individually, most are “medium” and get triaged to the bottom of a backlog that never empties.
That flat list is a map of the doors. It is not a map of the route an intruder actually walks. A real attacker does not stop at one door. They treat each finding as a primitive that unlocks the next, composing low-severity weaknesses into a high-severity outcome. The reflected XSS lands a payload in an admin's browser; the admin session forges a configuration change; the changed configuration exposes an internal host; the internal host can reach the cloud metadata endpoint; the metadata endpoint hands over a credential; the credential assumes the powerful role. Six mediums become one critical. We map this from the attacker's chair in our color-team adversary reviews, and the through-line is blunt: we have all the nodes and almost none of the edges.
Why scanners stay inside one domain
The structural reason is architectural, not lazy. A web scanner is built to crawl HTTP, inject payloads, and grade responses. A cloud-posture tool is built to read IAM policies and bucket ACLs. A network scanner fingerprints ports and versions. Each lives in its own domain, with its own data model, and they rarely share state. So a chain that crosses domains (an XSS that becomes a config change that becomes an SSRF that becomes an IAM escalation) has no single tool that can even represent it, let alone reproduce it.
The result is a systematic blind spot. The two highest-yield real-world paths are both cross-domain:
- SSRF → cloud metadata → IAM escalation. A request-forgery bug in a web app is a medium on its own. Pointed at
169.254.169.254it becomes a credential-theft primitive; the stolen role, if it caniam:PassRoleor assume another role, becomes account takeover. The web finding and the cloud finding sit in two different reports and neither tool draws the arrow between them. - Container escape → node credential → cloud metadata. An exposed Docker socket or a privileged pod is a container-runtime finding. The node's service-account token and the node's access to the cloud metadata service are infrastructure facts. Joined, they are a cluster-wide compromise.
A precedent that is exactly one CVE old
The cross-domain trust assumption that scanners miss is not theoretical. Consider the wave of Model Context Protocol (MCP) servers shipped by open-source projects through 2025 and 2026. CVE-2026-33032 is a confirmed instance: an MCP endpoint in a widely deployed web-server management tool exposes tool-invocation endpoints with no authentication, on the assumption that “localhost is trusted.” That assumption holds right up until the host is bound to 0.0.0.0, proxied, or reachable through a server-side request forgery from the very web app it manages.
That is the whole problem in one bug. The MCP server is “safe” in isolation: it is on localhost. The web app is “safe” in isolation: its SSRF is a medium. The edge between them (SSRF reaching the localhost-trusting tool endpoint) is where reachable becomes exploitable. A scanner that tests the web app and a scanner that tests the management tool will each report a manageable finding. Only a tool that follows the edge sees the command-execution path.
Building the edges, safely
Reproducing a cross-domain chain responsibly means proving each hop without weaponizing the whole path against production. The discipline we apply:
- Each hop is its own evidence. The SSRF hop proves only that an attacker-influenced URL reaches an internal address, not that we exfiltrated a credential. The metadata hop, where authorized and scoped to a lab or a customer-owned scratch account, proves reachability of the credential endpoint. The chain is asserted from linked, individually-verified hops, not from one destructive end-to-end run.
- Stop at proof of reachability for the dangerous hops. For an unauthenticated tool endpoint in the MCP class, the safe proof is a read-only call (“list config”) from an unauthorized origin, never a state-changing tool. Reachability plus a benign read is sufficient to mint the finding.
- The chain is the severity. Three mediums that compose into account takeover are reported as one critical with the path drawn, because that is what the defender has to fix, not three tickets that each look optional.
Here is the shape of a defender-side reachability probe for the SSRF → metadata edge. It confirms the arrow exists, it does not steal anything:
# Edge probe: does the web app's request-forgery reach the metadata service?
# Run against your OWN staging app + your OWN metadata endpoint only.
# Asserts reachability of the credential surface; pulls NO credential.
TARGET="https://app.staging.example/fetch?url="
META="http://169.254.169.254/latest/meta-data/" # AWS IMDS root, no token path
code=$(curl -s -o /dev/null -w '%{http_code}' "${TARGET}$(python3 -c 'import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1]))' "$META")")
echo "metadata-root via app SSRF -> HTTP $code"
# A 200 here means the EDGE exists: the web bug can reach the cloud trust boundary.
# FINDING = reachable edge + a separately-confirmed assumable role. Stop here;
# do not request the credentials path. Reachability is the proof.
What this means for how you read a report
The next time a scan hands you a flat list of mediums, ask a different question of it. Not “which of these is worst?” but “which two of these touch?” A request-forgery and an over-permissioned role that never appear on the same page are, to an attacker, the same finding. A localhost-trusting management endpoint and any bug that can reach localhost are the same finding. The severity that matters is the severity of the path, and the path is the thing single-domain tools are structurally unable to see.
This is why we treat chains as first-class. The catalog has thousands of node-level probes, but the work that moves a customer's risk is authoring the cross-domain edges (web into infrastructure, infrastructure into cloud) and proving the ones that connect. The nodes tell you what is broken. Only the edges tell you what is exploitable.
How Celvex Sentry tests for this
Our continuous-monitoring suite carries the node-level probes for SSRF, request-forgery, container escape, exposed management endpoints, and cloud-role posture, plus a chain engine that joins them. When a low-severity web bug provably reaches an internal trust boundary, and that boundary provably hands an attacker a more powerful position, we mint a single Proof Capsule for the chain, with each hop's evidence and the fix attached. When the hops do not connect, we say so. A list of unconnected mediums is not a finding we inflate, and a connected path is not a finding we split.
Sources
Get your exposure check: full report in 4-24 hours
Real assessment on production-grade infrastructure. We draw the path, not just the dots. Paying customers get priority capacity.
Queue My Assessment