Image scanners flag every vulnerable package they find, including packages that never execute, so a single cluster can produce thousands of findings that no team can work through. Container vulnerability management is the continuous practice of finding, prioritizing, fixing and verifying vulnerabilities in container images and in the workloads that run from them. Priority should depend on what is deployed, loaded in memory and reachable by an attacker, not on raw CVE counts. This guide, current as of October 2026, explains how to separate exploitable vulnerabilities from dormant ones, run triage and remediation on runtime evidence, and track whether the actionable backlog is shrinking.
Key takeaways
- ✓A CVE found in an image carries far less risk than the same CVE in a package that is loaded in memory inside an internet-facing container.
- ✓Container CVEs should be prioritized by runtime presence, exploitability, internet exposure, privilege level and asset criticality, with CVSS treated as one input among several.
- ✓SBOMs, VEX statements and signed images let teams suppress non-exploitable findings with evidence instead of re-triaging them after every scan.
- ✓A fix is complete only when runtime evidence shows the patched image digest has replaced the vulnerable one everywhere it ran.
- ✓The ratio of total findings to actionable findings is a better success metric than the total CVE count.
What container vulnerability management actually covers
The work runs from image build to running workload: detecting known vulnerabilities, deciding which are exploitable in your environment, fixing them through rebuilds or upgrades, and confirming the fix reached production. NIST’s Application Container Security Guide (SP 800-190) treats image vulnerabilities as one risk category alongside registry, orchestrator, container runtime and host OS risks. Image scanning alone therefore covers only part of the problem.
The most useful distinction is between four states a vulnerable package can be in. Most scanners report only the first.
| State | What it means | Example | Default priority |
|---|---|---|---|
| Found in image | The package exists in a layer of an image in a registry or build cache | libxml2 in an old tag nobody deploys | Low: fix at the next base-image refresh |
| Deployed | The image digest is running as a pod, task or container | perl inside a running Debian-based API image | Medium: track, no urgent ticket |
| Loaded in memory | A running process has mapped the library or imported the module | libssl.so loaded by an nginx worker | High candidate: check exposure |
| Actively reachable | Loaded code can receive input an attacker controls | A vulnerable parser behind a public Ingress | Highest: fix on the shortest SLA |
Why CVE counts mislead in container environments
Scanners report everything present in an image, while attackers can only exploit code that runs and that they can reach. A typical general-purpose base image ships a shell, a package manager, compression tools and language runtimes the application never calls. Every CVE in those packages lands in the same queue as the CVE in your public API’s request parser.
Common low-value findings include:
- Dormant OS packages: curl, perl, tar or systemd libraries in a base image that the entrypoint process never invokes.
- Dev dependencies in production images: jest, webpack, gcc or a full JDK copied into the runtime image because the Dockerfile skipped a multi-stage build.
- Unused layers: a full distro userland under a statically linked Go binary that needs only the kernel and CA certificates.
- Unreachable code paths: a YAML library is loaded, but the unsafe load function named in the CVE is never called.
- Undeployed images: hundreds of stale tags in a registry that no cluster has pulled in months.
Data quality adds more noise. NIST has narrowed which CVEs receive full NVD enrichment, so many older CVEs now lack the CVSS scores and CPE data that scanners traditionally rely on. Tools such as Docker Scout compensate by pulling from CISA KEV, GitHub Advisory and Linux distribution trackers, and by matching on Package URLs (PURLs) instead of CPE strings alone.
Editor’s tip: Debian, Ubuntu and Red Hat often backport security fixes without changing the upstream version number. A scanner that compares only upstream versions will flag a patched package as vulnerable. Prefer scanners that read distro security trackers, and check “critical” OS findings against the distro’s own advisory before you open a ticket.
How to prioritize container CVEs by what is actually running
Combine runtime evidence with exploit and exposure context to answer one question. Can an attacker reach and trigger the vulnerable code in a workload that matters? A mature vulnerability prioritization model weighs these signals:
| Signal | What raises priority |
|---|---|
| Runtime presence | The image digest is running and a live process has loaded the package |
| Package reachability | The vulnerable function sits on a code path the application executes |
| Exploitability | A public exploit exists or the CVE is listed in CISA KEV |
| Internet exposure | The workload sits behind a public load balancer, Ingress or NodePort after NetworkPolicy and security groups are applied |
| Privilege level | The container runs privileged or as root, mounts hostPath, holds CAP_SYS_ADMIN, or uses a service account with broad cloud IAM permissions |
| Asset criticality | The workload runs in production and handles payment data, PII or credentials |
| Compensating controls (lower priority) | Read-only root filesystem, seccomp RuntimeDefault, dropped capabilities, egress restrictions or a WAF rule |
Prioritization matrix
| Runtime state | Internet-facing | Internal only | No network path |
|---|---|---|---|
| Loaded and reachable | P1: fix in 72 hours | P2: fix in 14 days | P3: next rebuild |
| Deployed, not loaded | P3: next rebuild | P3: next rebuild | P4: base refresh |
| Not deployed | P4: base refresh | P4: base refresh | P4: base refresh |
The SLA values are an example policy. Raise a cell by one tier when the CVE is in KEV or the workload is privileged.
Decision tree for a single finding
- Is the image digest running anywhere? If not, tag the finding P4 and fix it at the next base-image refresh. Do not open a ticket.
- Is the vulnerable package loaded by a running process? If not, assign P3 and record a VEX statement with the justification
vulnerable_code_not_in_execute_path. - Can untrusted input reach the workload, from the internet or from a less trusted namespace? If not, assign P2 or P3 depending on privilege.
- Is there a known exploit or KEV listing? If so, assign P1 regardless of CVSS.
- Does the workload run privileged or hold sensitive cloud permissions? If so, shorten the SLA and review the identity in the same ticket.
Worked example: a critical CVE vs. a medium one
| Factor | Scenario A: critical OpenSSL CVE | Scenario B: medium library CVE |
|---|---|---|
| CVSS (illustrative) | 9.8 | 6.1 |
| Workload | Nightly report-builder job, written in Go |
checkout-api, written in Node.js |
| Runtime state | libssl present but never loaded, because Go uses its own crypto/tls | Vulnerable path-handling package loaded on every request |
| Exposure | No ingress, egress only to an internal database | Public Ingress behind an AWS ALB |
| Identity | Read-only database credentials | IRSA role with write access to an S3 bucket |
| Decision | P3: rebuild on the 30-day base refresh, suppress with VEX | P1: upgrade the library within 72 hours, add a WAF rule today |
CVSS-only triage would send the team to Scenario A first. Runtime evidence shows that Scenario B is the real exposure.
What each detection method sees
Runtime signals are only as good as the method that collects them. eBPF-based runtime security observes process execution, library loads and network flows at the kernel level, without changing application code.
| Method | What it sees | What it misses |
|---|---|---|
| Static image scanning in CI | Every package in the image before deployment | Whether the image deploys, what loads, and exposure |
| Registry rescanning | New CVEs disclosed against images already pushed | Which digests are running, and drift from approved images |
| Agentless snapshot scanning | Running workloads’ disks and cloud configuration, at a point in time | In-memory library loads and live network behavior |
| eBPF runtime sensors with workload context | Loaded packages, executed processes, live connections, identity in use | Nodes where the sensor cannot run, such as node-less serverless platforms |
A remediation workflow from build to verified fix
A working remediation workflow scans at build, gates at admission, correlates findings with runtime telemetry, routes each actionable finding to an owner, and closes the ticket only when runtime evidence shows the fix is live. MITRE D3FEND’s container image analysis technique recommends scanning throughout the build workflow, but the build step is only the start.
- Build: run container image scanning with Trivy or Grype in CI. Fail the build only on fixable critical or KEV-listed CVEs. Generate a CycloneDX or SPDX SBOM, sign the image with cosign, and attach SLSA provenance.
- Registry: rescan stored images nightly, because new advisories arrive after the push.
- Admission: use Kyverno, OPA Gatekeeper or Sigstore policy-controller to reject unsigned images, mutable tags such as
:latest, and images without an SBOM attestation. - Runtime correlation: join scanner output with runtime data on running digests, loaded packages, exposure and identity, then assign a tier using the matrix above.
- Ownership: route each P1 and P2 finding to the owning team using Kubernetes labels (
team,app.kubernetes.io/name) or CODEOWNERS in the image repository. Unowned workloads go to the platform team. - Fix: choose a strategy from the table below. Open one ticket per image, not one per CVE, so a single rebuild can close 40 findings at once.
- Verify: confirm the new digest is running in every cluster and namespace and that no pod still runs the old one. Close the finding from runtime evidence, not from a registry rescan.
Sample triage queue
| Finding | Workload | Runtime state | Exposure | Decision | Owner / SLA |
|---|---|---|---|---|---|
| High, glibc | Envoy sidecar | Loaded | Internal | Upgrade the mesh proxy version | Platform / 14 days |
| High, perl | payments-worker | Deployed, not loaded | Internal | Remove at next rebuild with a multi-stage build | Payments / next rebuild |
| Critical, Log4j | legacy-batch:v2 tag | Not deployed | None | Delete the tag from the registry | Platform / no ticket |
Choosing a fix strategy
| Situation | Strategy | Mechanics |
|---|---|---|
| CVE in an OS package from the base image | Rebuild from a patched base | Bump the pinned base digest, or move to a distroless or minimal base to remove the package entirely |
| CVE in an application dependency | Upgrade the library | Update the lockfile, run tests, rebuild and redeploy through the normal pipeline |
| Package not loaded or code path unreachable | Suppress with evidence | Publish an OpenVEX or CSAF statement with a justification and a 90-day expiry, and reopen it if the runtime state changes |
| No fix yet, and the workload is exposed | Temporary runtime controls | Apply NetworkPolicy, a WAF rule, a seccomp profile and dropped capabilities, with a named owner and an expiry date |
What counts as evidence for a suppression? Runtime data showing the package was not loaded over a defined window, such as 14 days covering a full release cycle, plus a VEX statement tied to the image digest, an approver and an expiry date. A suppression without an expiry date becomes a permanent blind spot.
Kubernetes controls that keep the backlog small
- ✓Track sidecars as images: service-mesh proxies, log shippers and init containers inherit CVEs too, so give them their own platform-team ownership.
- ✓Catch drift between approved and deployed images: pin by digest and alert when a running digest has no matching signed build.
- ✓Enforce admission control: require signatures, digest pinning and Pod Security Admission “restricted” at the namespace level.
- ✓Segment namespaces by risk: isolate internet-facing namespaces with default-deny NetworkPolicy so a compromised edge pod cannot reach an internal P2.
- ✓Review workload identity: audit IRSA, GKE Workload Identity and Azure Workload Identity bindings, because an over-permissive role turns a medium CVE into a cloud-account compromise.
Container vulnerability management tools
The tools fall into two groups. Runtime-aware platforms prioritize CVEs using live workload context, and open-source or developer-first scanners report what is inside an image before it ships.
| Tool | Approach | Prioritization signals | Kubernetes coverage |
|---|---|---|---|
| Upwind | Agentless discovery plus eBPF runtime sensors | Reachability, loaded packages, internet exposure, exploitability | EKS, GKE, AKS, OKE |
| Wiz | Agentless snapshot scanning with runtime validation | Attack paths, loaded packages, exposure, exploitability | EKS, AKS, GKE, self-managed |
| Aqua Security | Inside-out: eBPF, sidecars, containerized agents | Reachability, loaded packages, exposure, image assurance policies | EKS, AKS, GKE, OpenShift, VMware |
| Sysdig Secure | Hybrid: agents and eBPF with Falco, plus agentless | In-use packages, reachability, exposure, exploitability, fixability | EKS, GKE, AKS, OpenShift, IKS, RKE/RKE2 |
Upwind
Upwind combines read-only agentless scanners for cloud inventory and misconfigurations with runtime sensors on VMs, containers and serverless workloads that see processes, network traffic and API calls. It filters out CVEs that are not loaded or not reachable, then ranks the rest by internet exposure and exploitability, including attack-path context. Before deployment, it scans IaC, plugs into CI/CD pipelines, tracks SBOMs, and traces runtime findings back to the line of code that introduced them. One Gartner reviewer wrote that “within minutes of connecting Upwind, we were able to understand our most critical vulnerabilities.”
- ✓Prioritizes on runtime evidence: loaded, reachable, exposed and exploitable
- ✓Supports Linux and Windows Server containers, on x86 and ARM Linux images
- ✓Traces runtime findings to code, so owners are found faster
Customer review rating as of October 2026: 4.8/5 from 88 reviews on Gartner Peer Insights.
Wiz
Wiz relies on agentless, snapshot-based analysis and attack-path context, and adds runtime scanning that checks which packages are loaded and active in memory. It scans Terraform, Kubernetes, CloudFormation and ARM templates, generates SPDX and CycloneDX SBOMs, and traces findings to a commit, Dockerfile or line of code. One reviewer on Gartner Peer Insights reported going “from hundreds of findings with no relevance to our use case to a handful of issues to resolve.”
- ✓Covers AWS, Azure and GCP quickly without agents
- ✓Uses attack-path analysis for prioritization
Consideration: one reviewer noted that its detection and response capabilities still need development.
Aqua Security
Aqua places instrumentation inside the workload using eBPF, sidecars and containerized agents. It weighs reachability, loaded packages, exposure and exploitability, and adds image assurance policies and runtime behavioral profiling. It also generates digitally signed SBOMs and traces runtime findings to code.
- ✓Includes mature image scanning, virtual patching and Kubernetes posture checks
- ✓Covers containers, VMs, serverless functions and Amazon ECS
Consideration: reviewers say onboarding and tuning require experienced staff, so the platform suits large enterprises better than small teams.
Sysdig Secure
Sysdig’s “In Use” prioritization flags vulnerabilities only in packages that are loaded and executing, then layers on reachability, exposure, exploitability and fix availability. Its runtime detection is built on Falco. One reviewer said: “We can now prioritize by filtering only the vulnerabilities that are actually in use.”
- ✓Supports a broad range of Kubernetes distributions, including OpenShift and RKE2
- ✓Detects container runtime threats well
Consideration: reviewers cite a steep learning curve and complex Falco rule configuration through Terraform.
Open-source container scanning tools
Open-source and developer-first scanners are the right choice for the build stage and for Docker image vulnerability scanning before deployment, but they see only the image, not what runs.
- Trivy: scans images, Dockerfiles, Kubernetes manifests and Terraform.
- Grype: an image scanner driven by a vulnerability database, often paired with Trivy.
- Clair: correlates vulnerability metadata with image features to reduce noise.
- Anchore Engine: scans layer by layer, with a policy engine for filtering findings.
- Docker Scout: uses PURL matching, KEV and distro advisories, SBOMs and VEX.
Hadolint often appears alongside these tools, but it is a Dockerfile linter, not a vulnerability scanner.
How Upwind fits a runtime-first vulnerability workflow
Upwind is the runtime-correlation and verification layer in the workflow above. CI/CD checks and SBOMs cover the build stage, sensor evidence assigns each finding a tier, and the same evidence confirms the old digest is gone after a redeploy. Teams that run most of their containers on AWS Fargate or other node-less platforms will get less from it, because the sensor needs node-level access and does not run there.
- ✓Routes P1 and P2 findings to Jira, ServiceNow or PagerDuty, and feeds AWS Security Hub and Azure Defender for Cloud
- ✓Assigns owners faster by tracing runtime findings to the code or Terraform and CloudFormation config that introduced them
- ✓Hands the SOC Threat Stories, with a timeline, root cause and response steps, when a vulnerable workload is actually attacked
- ✓Uses the Agentic Pack AI agents to validate exposure and generate fixes grounded in runtime context
Metrics and a checklist for cutting CVE noise
The metrics that prove progress measure actionable risk and speed to fix, not the total number of CVEs found.
| KPI | How to calculate it | Example target |
|---|---|---|
| Exploitable-CVE count | CVEs that are loaded, reachable and exploitable in production | Trending down week over week |
| MTTR for runtime-exposed CVEs | Time from P1 detection to the verified new digest running | Under 72 hours |
| Images rebuilt within policy | Running images whose base was refreshed within the policy window, divided by all running images | Above 90% on a 30-day window |
| Findings-to-actionable ratio | Total scanner findings divided by P1 and P2 findings | Rising as noise is filtered out |
| Expired exceptions | VEX suppressions past their expiry date and not re-reviewed | Zero |
A practical checklist for every production cluster:
- ✓Use multi-stage builds and minimal or distroless bases for every production image
- ✓Attach an SBOM, cosign signature and provenance to each image digest
- ✓Enforce admission policies that reject unsigned or tag-referenced images
- ✓Correlate findings with running digests and loaded packages before tickets open
- ✓Open one ticket per image, with an owner from labels or CODEOWNERS
- ✓Back suppressions with VEX, an approver and an expiry date
- ✓Close tickets only after runtime verification of the new digest
Effective container vulnerability management means fixing what is running, reachable and exploitable first. Treat everything else as scheduled maintenance handled by base-image refreshes, and back every suppression with evidence that expires.
FAQ
Why do raw CVE counts mislead in container environments?
Because image scanners report every vulnerable package present in an image, including packages that never execute. Attackers can only exploit code that is actually running and reachable, so total CVE counts often exaggerate real risk.
How should teams prioritize container CVEs?
Prioritize by runtime presence, package reachability, exploitability, internet exposure, privilege level, asset criticality, and compensating controls. CVSS should be treated as one input, not the only deciding factor.
What makes a container vulnerability actionable?
A finding becomes actionable when the vulnerable image digest is actually deployed, the package is loaded in memory, and the vulnerable code is reachable by untrusted input. Those are the vulnerabilities that should move to the front of the queue.
When is it appropriate to suppress a container vulnerability finding?
Suppress a finding when runtime evidence shows the package is not loaded or the vulnerable code path is not in use. The suppression should be backed by a VEX statement tied to the image digest, an approver, and an expiry date.
How do you verify that a container vulnerability is really fixed?
A fix is complete only when runtime evidence shows the patched image digest has replaced the vulnerable one everywhere it was running. Closing findings based only on a registry rescan is not enough.
