Safeguard
AI Security

How a Container Image Scanner Works (and Which One to Use)

A container image scanner inspects the layers, packages, and configuration inside an image to find known vulnerabilities before you ship it. Here is how the scan works and what separates a good tool from a noisy one.

Marcus Chen
DevSecOps Engineer
6 min read

A container image scanner reads the layers, operating-system packages, and application dependencies baked into a container image, then matches them against vulnerability databases to tell you what is exploitable before the image reaches production. If you build with Docker or push to a registry, a container image scanner is the cheapest security control you can add, and it catches a class of problems that source-code review never sees: the OpenSSL version in your base image, the abandoned transitive dependency three levels deep, the curl binary you never asked for.

This post walks through what actually happens during a scan, what the output means, and how to tell a useful scanner from one that drowns you in findings.

What a scan actually inspects

A container image is a stack of read-only filesystem layers plus a JSON manifest. A scanner unpacks those layers and builds an inventory of everything installed. That inventory usually breaks into three buckets.

The first is OS packages: the apt, apk, yum, or dnf metadata that records which Debian, Alpine, or Red Hat packages are present and at what version. The second is language dependencies: the requirements.txt, package-lock.json, go.sum, or pom.xml artifacts your application ships. The third is loose files and binaries that were copied in without a package manager, which are harder to identify and where naive scanners go blind.

From that inventory the scanner produces a software bill of materials, then cross-references each component against feeds like the National Vulnerability Database, GitHub Security Advisories, and distro-specific security trackers. The match produces a list of CVEs, each with a severity and, ideally, a fixed version.

How matching works, and where it goes wrong

The matching step sounds simple: package openssl 3.0.11 has CVE-X, you have openssl 3.0.11, therefore you are vulnerable. In practice, distributions backport security fixes without bumping the upstream version number. Debian might patch OpenSSL and leave the version string looking old. A scanner that only compares upstream versions will report a CVE that Debian already fixed, and you will spend an afternoon chasing a false positive.

Good scanners consume distro security metadata so they know a backported fix landed. This is the single biggest quality difference between tools. When you evaluate a scanner, point it at a patched base image like debian:12-slim and count how many findings it reports that the distro has already marked "not affected" or "fixed." A high count means noise.

Reading the output without drowning

A fresh scan of a typical Node or Python image can return dozens of findings. Triage in this order:

Start with severity plus a known fix. A critical CVE with a patched version available is your first move: bump the base image or the dependency and rescan. Next, look at whether the vulnerable package is actually reachable. A CVE in a library your code never calls is real but lower priority than one on your request path. Finally, check exploit maturity. A vulnerability with a public exploit and evidence of active use in the wild jumps the queue regardless of raw CVSS.

Software composition analysis tooling shines here because it can flag whether a flaw sits in a direct or a transitive dependency; an SCA scanner such as Safeguard can surface the full dependency path so you know which line in which manifest to change. That path matters, because you cannot fix a transitive CVE by editing your own imports.

Where to run the scanner

There are three natural checkpoints, and mature teams use all three.

In CI, scan the image right after docker build and fail the pipeline on new critical findings. This is the gate that stops regressions. Keep the threshold honest: fail on critical-and-fixable, warn on everything else, or you will train developers to ignore the wall of red.

In the registry, run a scheduled rescan of images already pushed. New CVEs are disclosed daily, so an image that was clean on Tuesday can be vulnerable on Friday without a single byte changing. Registry scanning catches that drift.

At admission, in Kubernetes, an admission controller can block images that fail policy from being deployed at all. This is the backstop for images that bypassed CI.

A minimal CI example

Here is the shape of a scan step you can drop into most pipelines. The exact binary varies, but the flow is universal:

# build the image
docker build -t myapp:${GIT_SHA} .

# scan it, fail the build on fixable criticals
trivy image \
  --severity CRITICAL,HIGH \
  --ignore-unfixed \
  --exit-code 1 \
  myapp:${GIT_SHA}

The --ignore-unfixed flag is the one people forget. Without it you get blocked by vulnerabilities that have no patch, which helps nobody and just teaches the team to add || true to the step.

What to look for when choosing a tool

A few criteria separate the useful scanners from the checkbox ones. Distro backport awareness, covered above, is first. Second is SBOM output in a standard format like CycloneDX or SPDX, so the results are portable and auditable. Third is coverage across ecosystems, not just OS packages; if the tool cannot parse your go.sum or your Cargo.lock, half your attack surface is invisible. Fourth is a sane way to suppress accepted risks with an expiry, so an ignore file does not silently hide a finding forever.

If you are comparing commercial options, weigh how the pricing scales with image count and how noisy the defaults are. Our pricing page and the Snyk comparison walk through those trade-offs in more detail.

FAQ

Is a container image scanner the same as an SCA tool?

They overlap. SCA focuses on application dependencies declared in manifests; a container image scanner adds OS packages and files installed inside the image layers. Most modern container scanners include SCA capabilities, so the categories are converging.

Does scanning slow down my build?

Not meaningfully. A scan of a typical image finishes in seconds to a couple of minutes, most of which is downloading or updating the vulnerability database. Cache the database between runs and the overhead is negligible.

Can a scanner find zero-day vulnerabilities?

No. A container image scanner matches against known, published CVEs. It cannot find a flaw that has not been disclosed. Its value is making sure you are not shipping problems the whole world already knows about.

Should I scan base images or only my final image?

Scan the final image, because it contains everything, including the base. But choosing a minimal, well-maintained base image up front is the cheapest way to reduce findings, so treat base image selection as part of the same hygiene loop.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.