Container Image Scanning: A Complete Guide to Securing Your Containers
Container images bundle your application code with an entire OS filesystem, system libraries, and runtime dependencies. A single image can contain hundreds of packages — each with its own vulnerability history. Container image scanning analyzes every layer to find what is vulnerable, misconfigured, or malicious before the container reaches production.
What Is Container Image Scanning?
Container image scanning is the automated process of analyzing the contents of a container image — layer by layer — to identify security vulnerabilities, malware, hardcoded secrets, misconfigurations, and license compliance issues. Scanners decompose each image layer, catalog every installed package (both OS and application), match them against vulnerability databases, and generate a Software Bill of Materials (SBOM).
Scanning should happen at multiple points: when the image is built in CI, when it is pushed to a container registry, and continuously in the registry as new CVEs are published. Admission controllers in Kubernetes can enforce that only scanned, policy-compliant images are allowed to run.
What Container Scanners Detect
OS Package CVEs
Known vulnerabilities in OS packages like openssl, glibc, curl, and zlib. The most common finding category — a typical base image has 50–200 CVEs.
App Dependency Vulns
Vulnerabilities in language-specific packages (npm, pip, Maven, Go modules) installed inside the image.
Malware & Trojans
Cryptominers, backdoors, and trojanized binaries embedded in image layers. Detected via ClamAV and YARA signature matching.
Secrets in Layers
API keys, passwords, private keys, and tokens accidentally baked into image layers during build. Even deleted files persist in earlier layers.
Misconfigurations
Running as root, exposed sensitive ports, missing HEALTHCHECK, using latest tag, and missing USER directive in Dockerfile.
Outdated Base Images
Base images older than 90 days or using deprecated versions (node:10, python:2.7, centos:6) that no longer receive security patches.
How Container Scanning Works
Layer Decomposition
The scanner pulls and unpacks the image, analyzing each layer independently. This reveals files added, modified, or deleted at each build step.
Package Cataloging
OS packages (dpkg, rpm, apk) and language packages (package.json, requirements.txt, go.sum, pom.xml) are inventoried to build a complete SBOM.
Vulnerability Matching
Each package is matched against vulnerability databases — NVD, OSV, GitHub Advisory, Alpine SecDB, Debian Security Tracker, and vendor-specific databases.
Policy Evaluation
Findings are evaluated against organizational policies: CVSS thresholds, blocklisted packages, required base images, and compliance framework requirements.
Container Security Best Practices
Build Phase
Deploy Phase
Where to Scan: Build, Registry, and Runtime
A common mistake is scanning at exactly one point in the lifecycle. Each stage catches problems the others cannot, and a mature program uses all three.
Scanning in CI
Scanning at build time gives developers immediate feedback while the Dockerfile is still open in their editor. A typical GitHub Actions step runs trivy image --exit-code 1 --severity CRITICAL,HIGH myapp:$SHA right after docker build, failing the pipeline before the image is ever pushed. The limitation: CI scanning is a point-in-time check. An image that passed cleanly on Monday can be affected by a critical CVE published on Wednesday.
Scanning in the Registry
Registry scanning solves the freshness problem. Because the vulnerability database changes daily while your images do not, continuous re-scanning of stored images (ECR enhanced scanning, Harbor with Trivy, or a platform scanner polling the registry) surfaces newly disclosed CVEs in images already running in production. When Log4Shell dropped, teams with registry scanning knew within hours exactly which images and which workloads were affected; teams with CI-only scanning had to rebuild everything just to find out.
Runtime Correlation
The final stage correlates scan results with what is actually running. A critical CVE in an image with zero running instances is a backlog item; the same CVE in a container serving internet traffic is an incident. eBPF-based runtime sensors go further by observing which packages and libraries are actually loaded into memory — in practice only a fraction of the packages in an image are ever executed, which lets you deprioritize vulnerabilities in code that never runs. TigerGate pairs its image scanner with an eBPF agent for exactly this reason: scan findings plus runtime context yields a much shorter, more honest priority list.
Base Image Strategy: The Highest-Leverage Fix
Most CVEs in a typical image come from the base layer, not from your application. Choosing a smaller base is the single highest-leverage change you can make. Moving a Node.js service from node:20 (a full Debian image with roughly 800 packages) to node:20-slim typically cuts findings by more than half; moving to a distroless or Chainguard-style image can reduce the CVE count to near zero, because there is no shell, no package manager, and almost no userland left to be vulnerable.
The trade-offs are real but manageable. Distroless images are harder to debug (no shell to kubectl exec into — use ephemeral debug containers instead), and Alpine's musl libc occasionally causes subtle incompatibilities with software built against glibc. Multi-stage builds resolve most of the friction: compile in a full-featured builder image, then copy only the binary and its runtime dependencies into the minimal final stage.
Equally important is establishing a small set of golden base images maintained by a platform team. Instead of every service choosing its own base, teams inherit from an internal image that is rebuilt weekly, patched centrally, and pinned by digest. When a base-layer CVE lands, one rebuild plus automated downstream rebuilds patches the entire fleet — rather than hunting through dozens of Dockerfiles.
Handling Scanner Noise Without Ignoring Real Risk
Teams that fail with container scanning usually fail the same way: they turn on a scanner, see 4,000 findings across their registry, and quietly stop looking at the dashboard. Avoiding that outcome requires deliberate policy, not more scanning.
The goal is a scanning program developers trust: a red build should mean “this is genuinely dangerous and fixable right now,” and nothing else.
Enforcing Scan Policy in Kubernetes
Scanning without enforcement is advisory. Kubernetes admission control is where policy becomes mandatory: a validating admission webhook (Kyverno, OPA Gatekeeper, or a scanner-integrated controller) intercepts every pod creation and rejects images that violate policy before they are scheduled.
Effective admission policies are usually simple: require images from approved registries only, require a valid Cosign signature from your CI identity, reject images whose latest scan is older than a defined window or contains fixable critical CVEs, and reject workloads requesting privileged mode or writable root filesystems. Kyverno's verifyImages rule handles signature checks declaratively, and its audit mode lets you observe what would be blocked before enforcing — essential for rolling out policy in a busy cluster without breaking deployments.
The SBOM you generated at build time closes the loop here. Because the SBOM is attached to the image as a signed attestation, incident responders can answer “which running workloads contain this package?” with a query instead of a fleet-wide re-scan — the difference between a fifteen-minute answer and a multi-day scramble when the next Log4Shell-class event arrives.
Scan Container Images with TigerGate
TigerGate scans container images for vulnerabilities, malware, secrets, and misconfigurations — then monitors running containers with eBPF for runtime anomaly detection.