Container Security Kubernetes

Container CVE Management: How to Handle Vulnerabilities in Docker Images and Kubernetes Clusters

Container CVEs behave differently from host CVEs. Layer inheritance means a single vulnerable base image can propagate across hundreds of workloads. Here's how to find, triage, and fix them systematically.

CVEasy AI Research Team · February 28, 2026 · 11 min read
Container vulnerability scanning pipeline

One vulnerable base image layer multiplied across 200 running containers. SBOM-based scanning catches this class of vulnerability that traditional host scanners completely miss.

Traditional vulnerability scanners were built for hosts, physical or virtual machines with an operating system you can query directly. They install agents, talk to APIs, and interrogate the running system. Containers break all of those assumptions. Your scanner can't install an agent in a 5MB distroless image. It can't query a container that's already terminated. And it has no visibility into the 47 layers that make up your python:3.11-slim base image.

Container security requires a different scanning model, a different remediation workflow, and a different way of thinking about what "patched" even means in an ephemeral, immutable infrastructure world.

The scale problem: In a typical Kubernetes environment, a single CVE in libssl in your Ubuntu 22.04 base image can affect every container in your cluster that inherits from that base. A single patch (rebuilding and redeploying the base image) closes all of them simultaneously. But finding that single CVE requires SBOM-level analysis, not host-level scanning.

Why Container CVEs Are Different: Layer Inheritance and Base Image Sprawl

A Docker image is a stack of read-only layers. When you write a Dockerfile, you typically start with FROM ubuntu:22.04 or FROM python:3.11-slim. That base image contains an entire Linux userspace, libc, OpenSSL, curl, apt, and dozens of other packages, each of which can have CVEs.

Your application layers sit on top. They add your runtime, your dependencies, your application code. But every CVE in every layer below yours is also in your image, and therefore in every container spawned from that image.

The sprawl problem emerges from two patterns:

Triaging CVEs: Base Image Layer vs. Application Layer

The first triage question for any container CVE is: which layer does it live in? This determines the remediation path entirely.

Base Image Layer CVEs

These are in system packages (libc6, openssl, libssl3, curl, etc.) that came from the base image. Remediation requires updating the base image and rebuilding all images that inherit from it. You don't need to change application code. The fix is a base image bump in your Dockerfile's FROM line, followed by a full rebuild and redeploy.

Application Layer CVEs

These are in your declared dependencies. Python packages in requirements.txt, npm modules in package-lock.json, Java libraries in pom.xml, Go modules in go.sum. Remediation requires updating the dependency version in your manifest, then rebuilding. This may or may not require code changes depending on the nature of the update.

The Exploitability Question

Container CVEs have a higher false-positive rate than host CVEs because many vulnerabilities only affect functionality that a container doesn't use. A CVE in OpenSSL's server-side TLS implementation might be present in a container that only makes outbound HTTP connections and never listens on a TLS socket. The vulnerability exists in the binary but is functionally unexploitable in that container's context.

Tools like Grype and Trivy are starting to incorporate VEX (Vulnerability Exploitability eXchange) data to flag this, but as of 2026, this analysis is still largely manual. The heuristic: base image CVEs affecting networking libraries in containers that don't handle network-facing workloads are lower priority than the CVSS score suggests.

SBOM Generation with Syft and Grype

An SBOM (Software Bill of Materials) is a machine-readable inventory of every package in your container image, including versions, package manager origin, and layer attribution. It's the foundation of container-level vulnerability scanning.

Generating SBOMs with Syft

# Install Syft
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

# Generate SBOM for a local image in SPDX JSON format
syft myapp:latest -o spdx-json > myapp-sbom.spdx.json

# Generate SBOM for an image in your registry
syft registry:myregistry.io/myapp:v1.2.3 -o spdx-json > myapp-sbom.spdx.json

# Generate SBOM in CycloneDX format (required for some compliance frameworks)
syft myapp:latest -o cyclonedx-json > myapp-sbom.cdx.json

# Generate SBOM including layer attribution (shows which Dockerfile layer added each package)
syft myapp:latest -o json | jq '.artifacts[] | {name, version, locations}'

Scanning SBOMs with Grype

# Scan a local image directly
grype myapp:latest

# Scan from a previously generated SBOM (much faster, no image pull required)
grype sbom:myapp-sbom.spdx.json

# Output only CVEs with a fix available (reduces noise significantly)
grype myapp:latest --only-fixed

# Output as JSON for pipeline integration
grype myapp:latest -o json > myapp-vulns.json

# Filter by severity (only Critical and High)
grype myapp:latest --fail-on high

# Scan with VEX data to suppress known false positives
grype myapp:latest --vex myapp.vex.json
CI/CD integration pattern: Run Grype in your CI pipeline on every image build. Use --fail-on critical to block deploys of images with critical unpatched CVEs. Store the SBOM as a build artifact alongside the image digest. This creates an auditable record of the vulnerability state at build time for compliance purposes.

Kubernetes Namespace Isolation and CVE Risk

In a Kubernetes cluster, namespace isolation affects how severely a container CVE can be exploited if an attacker does gain code execution. A CVE that enables container escape (breaking out to the host) is dramatically more serious than one enabling lateral movement within the same namespace.

Key isolation controls that affect CVE severity assessment:

Image Signing with Cosign

Image signing ensures that the container image running in your cluster is the exact image that passed your security scanning pipeline, not a tampered version, not an image pulled from a different registry, not an older version with known vulnerabilities.

# Install Cosign
brew install cosign  # macOS
# or
curl -O -L https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64

# Generate a key pair (or use keyless signing with OIDC in CI)
cosign generate-key-pair

# Sign an image after it passes your security scan
cosign sign --key cosign.key myregistry.io/myapp:v1.2.3

# Verify signature before deployment (can be integrated into admission controllers)
cosign verify --key cosign.pub myregistry.io/myapp:v1.2.3

# Attach SBOM as a signed attestation
cosign attest --key cosign.key --predicate myapp-sbom.spdx.json \
 --type spdx myregistry.io/myapp:v1.2.3

# Verify SBOM attestation
cosign verify-attestation --key cosign.pub --type spdx \
 myregistry.io/myapp:v1.2.3

In Kubernetes, enforce signed images using the Sigstore Policy Controller or OPA/Gatekeeper admission webhook. Any image without a valid signature is rejected before it can run.

CVE Remediation vs. Image Rebuild: When to Do What

The container remediation decision tree differs from traditional patching:

Automation with Dependabot and Renovate

Manual image updates don't scale. In a polyglot microservices environment with 50+ services, you need automated PR creation for dependency updates.

Dependabot for Container Images (GitHub Actions)

# .github/dependabot.yml
version: 2
updates:
 # Monitor Python package dependencies
 - package-ecosystem: "pip"
  directory: "/services/api"
  schedule:
   interval: "weekly"
  open-pull-requests-limit: 10

 # Monitor Docker base images
 - package-ecosystem: "docker"
  directory: "/"
  schedule:
   interval: "weekly"
  labels:
   - "dependencies"
   - "container"

Renovate for More Complex Pinning Strategies

// renovate.json
{
 "extends": ["config:base"],
 "packageRules": [
  {
   "matchPackagePatterns": ["^ubuntu", "^debian", "^alpine", "^python"],
   "matchDepTypes": ["stage"],
   "groupName": "base images",
   "schedule": ["every weekend"]
  },
  {
   "matchDepTypes": ["dependencies"],
   "matchUpdateTypes": ["patch"],
   "automerge": true,
   "automergeType": "pr"
  }
 ],
 "vulnerabilityAlerts": {
  "enabled": true,
  "labels": ["security"]
 }
}
The complete container VM stack: Build: Syft generates SBOM + Grype scans + Cosign signs. Registry: Store SBOM attestations alongside image digests. Deploy: Admission controller verifies signature before scheduling. Runtime: Continuous SBOM scanning against live CVE feeds. CVEasy AI ingests Grype JSON output and applies TRIS™ scoring with KEV and EPSS enrichment, so you prioritize container CVEs by actual exploit probability, not raw CVSS. Get early access →

Ready to take control of your vulnerabilities?

CVEasy AI runs locally on your hardware. Seven layers of risk intelligence. AI remediation in seconds.

Get Started Free Learn About BASzy AI

Related Articles