A docker scanner needs to check three distinct layers of a container image — the base OS packages inherited from something like debian:bookworm or alpine:3.19, the application-level dependencies installed on top (npm packages, Python wheels, Go modules), and the Dockerfile itself for insecure build patterns — and in practice most tools are genuinely strong at one or two of those layers rather than all three. Choosing a docker scanner without checking which layers it actually covers is the most common way teams end up with a false sense of coverage: a clean scan result that only ever looked at OS packages says nothing about a vulnerable dependency baked into the application layer.
What does OS-layer scanning actually catch?
This is the most mature part of docker scanner tooling and the layer every serious tool handles reasonably well: matching installed OS packages (from apt, apk, yum, depending on the base image) against vulnerability databases maintained by the OS distributions themselves and aggregated feeds like the National Vulnerability Database. A scan against a stale ubuntu:20.04 base image will reliably surface known CVEs in openssl, glibc, and other system libraries, and this is genuinely useful — a huge share of real container vulnerabilities trace back to a base image that hasn't been rebuilt in months, quietly accumulating patched-elsewhere CVEs the whole time.
Why does application-dependency scanning matter separately?
OS-layer scanning says nothing about the npm packages, Python libraries, or Go modules an application actually depends on, which is a completely different manifest with its own vulnerability history. A docker scanner needs to actually inspect the layers where package-lock.json, requirements.txt, or go.sum get baked into the image, extract the resolved dependency versions, and check those separately — this is effectively the same job SCA does outside a container context, applied to what ends up frozen inside the image. Tools that only advertise "container scanning" without being explicit about application-dependency coverage are worth double-checking here, because this layer is where a lot of exploitable, network-reachable vulnerabilities actually live, versus OS packages that may never be invoked by the running application at all.
What does Dockerfile-level scanning add?
This is the newest and least consistently implemented layer: checking the Dockerfile itself for patterns that create risk independent of any specific CVE — running as root instead of a dedicated non-root user, using ADD with a remote URL instead of COPY with a checksum, leaving build-time secrets baked into a layer instead of using build secrets or multi-stage builds, or pulling a base image by a mutable tag like latest instead of a pinned digest. None of these show up in a CVE database because they're structural risks, not known vulnerabilities, but they're exactly the kind of thing that turns a minor vulnerability into a serious compromise — a container running as root with a shell vulnerability has a much larger blast radius than the same vulnerability in a container that dropped privileges properly.
How do commercial docker scanner tools actually compare?
The landscape includes dedicated container-scanning specialists, broader SCA platforms that added container support, and cloud-native registries with built-in scanning bundled in. The honest differentiator across all of them is depth on the application-dependency layer and how current their vulnerability feeds are — a scanner with a stale CVE database is worse than no scanner at all, because it creates false confidence. Watching docker vulnerability news for how quickly a given tool's database picked up a newly disclosed, high-severity CVE (the way the community tracked coverage speed after past high-profile container CVEs) is a reasonable, if informal, way to judge a vendor's actual responsiveness versus its marketing claims. Comparisons between platforms like docker snyk coverage and dedicated SCA vendors are worth reading with this same lens — ask which layers each product actually scans, not just how many CVEs it claims to know about.
Where does image scanning fit in the build pipeline?
The strongest pattern scans at multiple points: on every build in CI so a vulnerable base image or dependency never makes it into a registry in the first place, and again on a schedule against images already in the registry, since new CVEs get published against images that haven't changed at all. Pairing this with runtime checks, or at minimum a policy gate that blocks deployment of images above a severity threshold, closes the gap between "we scanned it" and "we actually stopped the bad one from shipping" — a distinction that matters more than most teams initially assume when they first stand up a scanning pipeline.
FAQ
Does a docker scanner replace the need for SCA on application code outside containers?
Not entirely — if application code is deployed both inside and outside containers (a library shared across services, for instance), dependency scanning needs to run in both contexts, since a container scan only covers what's actually baked into that specific image.
How often should container images be rescanned after they're built?
On a regular schedule, at minimum weekly for anything running in production, because new CVEs get disclosed against unchanged images constantly. Relying only on a build-time scan misses everything discovered after the image shipped.
Do slimmer base images like Alpine reduce scanning burden?
They reduce the OS-layer attack surface since there are fewer packages to have a CVE, but they don't eliminate the need for scanning — application dependencies and Dockerfile-level risks are unaffected by the base image choice.
What's the biggest blind spot in most docker scanner setups?
Dockerfile-level and configuration risks (running as root, mutable tags, baked-in secrets) — these don't show up in CVE-based scanning at all and require a scanner that explicitly checks build patterns, not just package versions.