Container image scanning
In plain terms#
Your application code is only part of what ships. When you build a container image, you also bundle an operating system, system packages, and language runtimes, often hundreds of components you never chose directly (they came from the base image). Container image scanning inventories everything inside an image and checks it for known vulnerabilities.
It's SCA applied to the whole box your app runs in, not just its dependencies.
Why it matters#
A pristine codebase running on a two-year-old base image is still exposed to every unpatched
OS-level CVE in that image. Base images drift out of date silently, and "it built fine" says
nothing about whether openssl inside it has a critical vulnerability. Image scanning is what
keeps the gap between "my code is clean" and "my container is clean" from surprising you.
Where it fits#
- Artifact: a built container image (local, or in a registry, referenced by tag or digest).
- Stage: at build time (scan before you push) and continuously in the registry (a clean image today can have a new CVE tomorrow, the image didn't change, the world did).
How it works#
A scanner reads the image layer by layer, enumerates OS packages (from the apk/apt/rpm
databases) and language dependencies, and matches them against vulnerability feeds. Good tools
map findings to the specific layer that introduced them (so you know whether it's your
Dockerfile or the base image at fault) and tell you if a fixed package version exists.
Popular & reputable tools#
| Tool | Notes |
|---|---|
| Trivy | OSS, very widely used; scans images, filesystems, and more |
| Grype | OSS, from Anchore; pairs with the Syft SBOM tool |
| Clair | OSS; powers registry-side scanning (e.g. Quay) |
| Docker Scout, Snyk Container | Commercial/integrated options |
Common pitfalls#
- Choose a small base image. Distroless or Alpine/Chainguard images carry far fewer
packages, and therefore far fewer CVEs, than a full
ubuntubase. The cheapest fix is often a smaller base. - Unreachable OS CVEs. Many flagged packages aren't used by your app; prioritize by exposure and reachability, not raw count.
- Scan by digest. Tags move; pinning to an image digest makes scans reproducible.
images control runs Trivy against each container image a component declares, normalized to SARIF. Combined with the component's exposure and criticality, image CVEs are ranked into an actionable order rather than a raw count. See how to declare images in a Saga in the docs.Grype can serve the same control, on its own or beside Trivy. Both sets of findings arrive in one report, ranked by the same risk model. Two matchers draw on different advisory sources, so where they disagree that difference is a statement about coverage neither makes alone.
Keep learning#
- SCA, vulnerabilities in your application dependencies
- SBOM, the parts list image scanning builds on
- IaC misconfiguration, securing the Dockerfile itself