Cloud and Containers

Prioritizing Cloud CVEs by Internet Exposure and Reachability

22 September 2026 10 min read

A single mid-sized cloud account, scanned with a standard CSPM or container scanner, routinely returns finding counts in the tens of thousands once every base image, Lambda layer, and EC2 fleet gets tallied. Sort by CVSS severity alone and the critical bucket can still run to five figures. No security team triages 40,000 criticals in a sprint, so most of them get triaged by neglect: a spreadsheet nobody opens, a Jira backlog that grows faster than it shrinks. The fix is not a better CVSS calculator. It is a prioritization model that asks whether a finding is actually exposed to the internet, actually reachable at runtime, and actually dangerous if the host behind it is compromised.

Why CVSS alone leaves 40,000 criticals in a single cloud account

CVSS Base Score measures intrinsic severity: how bad the flaw is in the abstract, assuming an attacker can reach it under ideal conditions. It says nothing about whether your deployment gives an attacker that path. A CVE with Attack Vector: Network and a 9.8 base score gets the same label whether the vulnerable service sits on a public load balancer or inside a private subnet with no route to an internet gateway, reachable only from a jump host that itself requires a hardware token.

The practical result: dependency and OS-package scanners flag every CVE for every installed package, regardless of whether that package is loaded, called, or network-facing. A base image with an outdated OpenSSL, glibc, and curl can generate two or three dozen CVE rows on its own, multiplied across every service built from that image. None of this is wrong data, it is just undifferentiated data. EPSS (Exploit Prediction Scoring System) helps by estimating real-world exploitation probability instead of theoretical severity, and it is a meaningful second filter, but it still does not know your VPC topology or your IAM policies. Cutting the list down to something an engineering team will actually work through requires signals CVSS was never designed to carry: exposure, reachability, and identity blast radius.

Exposure signals: public IP, security group, load balancer path, WAF in front

Exposure is a network-topology question, not a vulnerability-database question. Answering it means reconstructing the actual path from the public internet to the vulnerable resource, using the cloud provider’s own graph: elastic network interfaces, subnet route tables, internet gateway attachments, security groups or NSGs, load balancer listeners and target groups, and any CDN or WAF sitting in front.

A workable exposure check looks at conditions like these, in order of how much they change the finding’s priority:

  • Direct public IP with an open security group. The ENI has a public IPv4 or IPv6 address, the subnet route table points to an internet gateway, and the attached security group allows inbound traffic from 0.0.0.0/0 on the vulnerable port. This is the highest exposure band; treat it as internet-reachable at the network layer by default.
  • Fronted by a load balancer only. The instance itself has a private IP, and its security group only allows traffic from the load balancer’s security group. Exposure exists, but only through whatever paths the load balancer forwards, so a vulnerability on a port the ALB never routes to is not actually exposed even though the host technically sits in a public-facing fleet.
  • WAF or CDN in front of the load balancer. A WAF does not close a vulnerability, but it can materially reduce exploitability for specific attack classes (path traversal, common SQLi patterns, known CVE signatures), which is a legitimate, bounded downgrade for scoring purposes, not a reason to close the finding.
  • Private subnet, no route to an internet gateway, no public IP anywhere in the chain. This is the lowest exposure band. It does not mean the finding is safe, since internal lateral movement is still real, but it removes “internet-reachable” as the escalation reason.

The mechanical part of this, walking every ENI, route table, and security group rule across every account and region, is exactly the kind of graph-building that attack surface mapping tools exist for. A module that continuously maintains this graph, such as the attack surface management view in a cloud-native scanning pipeline, turns “is this exposed” from a manual Console lookup into a queryable attribute on every finding.

Runtime reachability: is the vulnerable package actually loaded and called

Exposure answers whether traffic can reach the host. Reachability answers a narrower and often more decisive question: is the vulnerable code path actually loaded into the running process, and is it ever invoked. Static SCA (software composition analysis) scanning reads manifests and lockfiles; it flags a CVE the moment a vulnerable package version appears in package.json, requirements.txt, or a JAR’s dependency tree, whether or not that package ever executes.

Log4Shell (CVE-2021-44228) is the canonical example. Log4j-core sat on the classpath of an enormous number of Java applications, but a meaningful share of those applications never called the specific logging pattern that triggered the JNDI lookup, either because they used a different logging façade, set a log level that skipped the vulnerable code path, or never logged attacker-controlled input at all. A scanner that stops at “log4j-core 2.14.1 is present” cannot distinguish those cases. A scanner that instruments the JVM classloader, or traces actual function calls with an eBPF probe or language-level hook, can.

Building this signal takes runtime instrumentation appropriate to the stack: JVM classloading hooks for Java, import hooks for Python, require/import tracing for Node, and eBPF-based syscall or library-load tracing at the OS level for anything else. The output you want per finding is binary but well-evidenced: loaded and called, loaded but never called, or never loaded at all. Platforms built around continuous reachability analysis, rather than point-in-time scans, keep this signal current as deployments change; SITEY’s network reachability module works this way, correlating live network paths with which services actually accept traffic on the affected port, so a finding on a host with no listener bound to that port gets automatically deprioritized instead of sitting in the critical queue on the strength of a manifest entry alone.

Identity blast radius: what the attached role can reach after compromise

Exposure and reachability describe how an attacker gets in. Blast radius describes what happens after they do, and it depends almost entirely on the identity attached to the compromised resource: the IAM role on an EC2 instance or Lambda, the service account on a GKE pod, the managed identity on an Azure VM.

A concrete way to score this: evaluate the attached role’s effective permissions (including any roles it can assume, cross-account trust relationships, and resource-based policies granting it access) and bucket the result.

Attached identity Practical consequence of compromise Blast radius weight
AdministratorAccess or equivalent wildcard policy Full account takeover, including IAM modification and data exfiltration across all services Maximum
Role can assume a higher-privilege role in another account Cross-account pivot; blast radius extends beyond the compromised account’s boundary High
Read/write on specific services (e.g. S3, RDS, Secrets Manager) scoped by resource ARN Data exposure limited to named resources, no lateral privilege escalation path Medium
Read-only, single resource, no PassRole or AssumeRole permissions Limited to the data already reachable through the running application Low

Tools like AWS IAM Access Analyzer, cloudsplaining, or PMapper compute this kind of effective-access graph by simulating policy evaluation rather than reading policy documents literally, which matters because resource policies, permission boundaries, and SCPs can each narrow or widen what a role can actually do. The output feeds directly into prioritization: a medium-exposure, medium-reachability finding on a host holding an administrator role can outrank a high-exposure finding on a host whose role can only read a single object in one S3 bucket.

Combining signals into a score engineers will accept without arguing

The fastest way to lose engineering buy-in is to hand them a single opaque number, a “risk score: 87” with no visible reasoning. Engineers who get paged for a finding want to see the inputs, not trust a black box. A transparent scoring approach that holds up under scrutiny keeps each signal as a separate, visible axis and combines them with a rule set the team agreed to in advance, rather than a machine-learned weight nobody can explain.

A workable structure: score exposure 0 to 3, reachability 0 to 2, and identity blast radius 0 to 2, then define explicit escalation rules instead of a single multiplied total, for example:

  • P1 (fix this week): Exposure of 2 or higher AND reachability confirmed (loaded and called) AND blast radius of 1 or higher.
  • P2 (fix this sprint): Exposure of 2 or higher AND reachability confirmed, but blast radius is 0, OR exposure is 1 with blast radius at maximum.
  • P3 (backlog, revisit on next scan): Reachability is 0 (package present but never loaded) regardless of exposure or blast radius, since there is no current path to exploitation.

This is a decision matrix, not a formula that hides its own logic, and that distinction is what earns engineer trust: everyone can see exactly why a finding landed in P1 and can dispute a specific input (maybe the security group is more permissive than the graph thinks) rather than the score itself. Platforms that automate this triage still need to expose the underlying evidence chain for exactly this reason; the AI triage stage of an automated pipeline is only useful to an on-call engineer if it shows which axis crossed which threshold and links back to the actual security group rule, the actual call trace, and the actual IAM policy document it read, not just a final label.

Validating the model: did exposure time actually drop after re-ranking

A prioritization model is a hypothesis until it is measured. The metric that matters is not how many findings got reclassified, it is whether the findings that stayed critical actually got remediated faster, and whether true internet-exposed, reachable vulnerabilities spent less time open than they did under CVSS-only ranking.

Track a small number of things on a recurring basis, ideally weekly:

  1. Median time-to-remediate for P1 findings under the new model, compared against the same metric for CVSS-critical findings in the prior quarter. If P1 dwell time is not meaningfully shorter, the re-ranking did not change engineering behavior, it just relabeled the backlog.
  2. Internet-exposed dwell time specifically. For findings where exposure is at maximum and reachability is confirmed, measure days-open independently from the rest of the backlog. This is the number that maps most directly to actual breach risk.
  3. Downgrade accuracy. Periodically sample findings marked P3 for “not reachable” and manually confirm they are in fact not loaded or not exposed. A reachability signal that is wrong in the optimistic direction (calling something safe when it is not) is far more costly than one that is wrong pessimistically.
  4. Recalculation frequency. Security groups, IAM policies, and load balancer target groups change continuously; a graph computed once a month is stale before the sprint ends. Recompute exposure and identity blast radius at least daily for anything already flagged as a finding, and after any change event where the cloud provider emits one (security group modification, IAM policy attachment, route table change).

Closing the loop also means confirming that a “fixed” finding is actually fixed, not just patched on paper. A patch that changes the package version without restarting the affected process, or that lands in a container image never redeployed, leaves the original exposure and reachability conditions unchanged. Re-testing the specific finding against live traffic, rather than trusting a patch command’s exit code, is the only way to know exposure time actually dropped; SITEY’s retest and closure phase runs this check automatically against the same reachability and exposure graph used for prioritization, so a finding only closes when the path that made it dangerous in the first place is verified gone.

None of these four signals, exposure, reachability, identity blast radius, or a transparent combination rule, replaces CVSS or EPSS. They sit on top of them, narrowing tens of thousands of theoretically critical findings down to the small number that are actually dangerous in your specific environment today. That distinction, between “critical in the abstract” and “critical right now, in this account, on this host,” is the entire point of cloud vulnerability prioritization.

About SITEY

SITEY is an autonomous vulnerability management platform. It discovers, validates, prioritizes, remediates and re-tests vulnerabilities through an eight-phase automated pipeline, unifying output from 17 integrated scanners. SITEY is self-hosted: it runs in your own infrastructure and your findings are stored there. Outbound connections are limited to licence activation and the optional services you enable, such as an AI provider, CVE enrichment and patch catalogues. Pricing is 599 USD per month or 5,999 USD for a perpetual lifetime license. See pricing or how the platform works.

SITEY closes the loop, not just the report.Discover, validate, fix and verify in your own infrastructure.

See pricing