A container security scan inspects a container image for known vulnerabilities in its operating-system packages and application dependencies, plus misconfigurations like running as root or embedded secrets, and reports them so you can fix issues before the image reaches production. The mechanics are simple; the hard part is that a naive scan of a common base image can return hundreds of CVEs, most of which don't matter for your workload. This guide covers what a container security scan actually examines, where to run it, and — the part that separates a useful program from a noisy one — how to prioritize the results.
What a container security scan looks at
A container image is layers: a base OS, packages installed on top, your application code, and its dependencies. A container security scan works through these layers and checks several distinct things.
The first and most common is OS package vulnerabilities. The scanner reads the package manifest — the dpkg database on Debian/Ubuntu, rpm on RHEL-family, apk on Alpine — enumerates every installed package and version, and matches them against vulnerability databases like the NVD and distro security trackers. This is where the big CVE counts come from, because base images ship dozens of system libraries.
The second is application dependency vulnerabilities: the npm, PyPI, Maven, or Go packages your app bundles. This overlaps with software composition analysis, and the best scanners cover both the OS layer and the language layer in one pass.
The third is configuration and hygiene: does the image run as root? Does it embed secrets or private keys in a layer? Does the Dockerfile use a floating latest tag that makes builds non-reproducible? These aren't CVEs but they're real risk, and a good scan flags them.
Running a scan locally
You can scan an image with open-source tooling before it ever leaves your machine. Trivy is a widely used, straightforward choice:
trivy image myapp:1.4.2
That prints a table of vulnerabilities grouped by severity. To focus on what you'd actually gate on:
trivy image --severity HIGH,CRITICAL --ignore-unfixed myapp:1.4.2
The --ignore-unfixed flag is doing real work: it hides CVEs for which no fixed version exists yet, so you only see issues you can actually act on. Grype is another common scanner with a similar model. Running a scan locally gives developers fast feedback and keeps obviously broken images out of the registry.
Where a container security scan fits in the pipeline
Effective scanning happens at more than one point, because vulnerabilities enter at different stages.
- Build time — scan the image as part of CI, right after it's built. This catches problems before the image is pushed and can fail the pipeline on new critical issues. It's the highest-leverage point because it stops bad images at the door.
- Registry — scan images sitting in your registry on a schedule. This matters because a CVE can be disclosed after an image was built. An image that was clean on Tuesday can be vulnerable on Friday when a new advisory drops for a package it contains, without a single byte changing.
- Runtime — scan or monitor what's actually deployed. This closes the gap between what you scanned and what's really running, which drift and manual deploys can open.
The registry-rescan point is the one teams most often miss. Your scan is a snapshot against a vulnerability database that updates daily; yesterday's clean image needs re-checking against today's advisories.
The prioritization problem
Here's the reality of container scanning: a scan of a full base image like ubuntu:22.04 or a fat node:20 image can report hundreds of CVEs. If you treat all of them as work, you'll burn out and ship nothing. Prioritization is the entire game.
Three filters do most of the reduction. First, fixability — an unfixed CVE is not actionable today, so --ignore-unfixed alone often cuts the list dramatically. Second, reachability and relevance — a vulnerability in a system library your application never invokes is far lower risk than one in a package on your request path. Third, exploit maturity — a CVE with a known exploit in the wild deserves attention over a theoretical one with no public proof of concept.
The single most effective structural fix, though, is upstream: use a smaller base image. Switching from a full OS base to a minimal or distroless image removes entire categories of packages — and therefore entire categories of CVEs — because the vulnerable library simply isn't present. A distroless or Alpine-based image often reports a fraction of the findings of a full base, not because the scanner is lenient but because there's genuinely less attack surface. Multi-stage builds that ship only the runtime artifacts, not the build toolchain, have the same effect.
Making scanning continuous
A one-time scan is a snapshot; security is a moving target. Wire scanning into the pipeline so it runs on every image build and re-runs against the registry on a schedule, and set a policy that fails builds on new critical, fixable issues rather than on the entire pre-existing backlog — otherwise the first scan blocks every merge and the team disables it.
Combining OS-layer and dependency-layer coverage in one tool avoids blind spots between them. A platform such as Safeguard can correlate a container security scan with the application's software composition analysis so a vulnerable library shows up once with full context, whether it arrived through the base image or the app's own dependencies. Our SCA overview explains that correlation, and the Academy has a walkthrough on setting fail thresholds that don't drown developers.
FAQ
What does a container security scan check for?
It checks for known vulnerabilities in the image's OS packages and bundled application dependencies, matched against vulnerability databases, plus misconfigurations like running as root, embedded secrets, and non-reproducible base tags. The best scanners cover both the OS layer and the language-dependency layer in a single pass.
Why does my container scan report hundreds of vulnerabilities?
Full base images ship dozens of system libraries, each of which can carry CVEs, so the raw count is often large. Most aren't relevant to your workload. Filter by fixability, reachability, and exploit maturity, and switch to a minimal or distroless base image to remove the vulnerable packages entirely.
When should I run a container security scan?
At build time in CI to stop bad images before they're pushed, on a schedule against your registry to catch CVEs disclosed after the build, and at runtime to cover drift between what you scanned and what's deployed. The registry rescan is the step teams most often overlook.
Does a smaller base image really reduce vulnerabilities?
Yes, substantially. Distroless and Alpine-based images contain far fewer packages than full OS bases, so there are simply fewer libraries that can have CVEs. Pairing a minimal base with multi-stage builds that exclude the build toolchain is the most effective way to shrink both the finding count and the real attack surface.