Docker image scanning works by unpacking an image's layers and inventorying every package inside — operating system packages from the distro's package database plus language dependencies from lockfiles and installed metadata — then matching that inventory against vulnerability advisories. It finds known CVEs, baked-in secrets, and risky image configuration. It does not execute the container, and it misses anything absent from both the metadata and the databases: your first-party code, compiled-from-source binaries, and vulnerabilities nobody has cataloged yet. Knowing exactly where that boundary sits is what makes scan results actionable.
How does docker image scanning actually work?
A scan is static filesystem analysis in four steps. First, the scanner pulls the image and unpacks its layers into the merged filesystem a running container would see. Second, it inventories software: OS packages read from the package manager's own records (/var/lib/dpkg/status on Debian-family images, the apk database on Alpine, the rpm database on Red Hat-family), and application dependencies read from what ecosystems leave behind — package.json files under node_modules, Python dist-info metadata, JAR manifests, Go build info embedded in binaries. Third, it normalizes everything into identifiers, typically purls like pkg:deb/debian/openssl@3.0.11-1. Fourth, it matches those identifiers against advisory sources — the distro security trackers (Debian, Ubuntu, Alpine secdb, Red Hat OVAL) for OS packages, and OSV, GitHub advisories, and NVD for application ecosystems — and reports each hit with severity and fixed-version data.
The detail that explains most scanner behavior: the whole pipeline reads metadata. If software entered the image in a way that left no package record — make install from source, a curl-piped binary, a vendored copy — the scanner is blind to it.
What does a scan find?
Four finding classes, in descending volume:
- OS package CVEs — usually the bulk of results, and mostly inherited from the base image rather than introduced by your Dockerfile. Good scanners attribute findings to layers so you can see the split.
- Application dependency CVEs — vulnerable npm, pip, Maven, and Go modules baked into the image, matched with fixed-version guidance.
- Secrets — API keys, tokens, and private keys left in files. The classic trap: a secret added in one layer and deleted in a later one is still present in the earlier layer and fully recoverable from image history.
- Configuration weaknesses — running as root, no
USERdirective, suspicious permissions — depending on the tool's rule set.
Why do results differ between scanners and between distros?
Run two scanners on the same image and the counts will differ; this is mostly a metadata-interpretation problem, not a quality ranking. The biggest cause is backports: enterprise distros fix CVEs in patched builds of old versions — the package says openssl 3.0.11-1ubuntu2.3 while the upstream fix landed in a later version number. A scanner that honors the distro's security tracker correctly marks it fixed; one matching raw upstream version ranges reports a false positive. Distros also publish their own severity assessments and explicit "will not fix" decisions for low-impact issues, which some tools surface and others ignore. When counts disagree, the tiebreaker question is always: which tool respected the distro's own advisory data for this package?
What does docker security scanning miss?
Docker security scanning is inventory-based, so its blind spots are structural. It does not analyze your first-party application code — injection flaws in your handlers need SAST and DAST, not an image scan. It cannot see software without metadata: source-built binaries and vendored code produce no package records. It knows nothing about runtime — the over-privileged container, the mounted Docker socket, and the hostile network policy are deployment properties, not image properties. And distroless or scratch-based images cut both ways: genuinely less attack surface, but also no package database, so scanning them well depends on SBOMs generated at build time, when the build system still knows what went in. Treat the scan as one layer of a container security program, not the program.
Where should scanning run: CI, registry, or runtime?
All three, doing different jobs. In CI, the scan is a gate: block on new critical findings with an available fix, so known-vulnerable images never ship — same new-findings-only discipline as any pipeline gate. In the registry, scanning is continuous re-evaluation: the image does not change, but the advisory databases change daily, and the image that passed cleanly in March may carry a critical in June. This re-scan-on-new-advisories loop is the piece ad-hoc scanning misses entirely, and it is where continuous SCA monitoring does the same job for images that it does for repositories. At runtime, deployment context — which images actually run, and where — should drive prioritization, because a critical in a dead image is paperwork while a medium in an internet-facing workload is real. Consolidating those three feeds into one prioritized queue rather than three consoles is, in practice, the argument for a platform over point tools.
Keep the mechanical hygiene cheap: pin base images, rebuild on a schedule so upstream fixes flow in, use multi-stage builds so toolchains stay out of the final image, and generate an SBOM per build so the inventory exists independent of the scanner.
FAQ
How is docker image scanning different from SCA?
Image scanning is software composition analysis applied to a container artifact — the same advisory matching, extended to the OS package layer and image-specific concerns like layer-trapped secrets. Repository SCA sees your declared dependencies; the image scan sees what actually shipped, base image included.
Should you scan base images or final images?
Final images, always — they are what runs, and they contain the base plus everything you added. Separately scanning and curating a small set of approved base images is a high-leverage supplement, since base layers typically contribute most OS-level findings across every downstream service.
How do you reduce image findings quickly?
Three moves, in order of impact: switch to a smaller or fresher base (slim, Alpine, or distroless variants); rebuild regularly so already-released distro fixes are picked up; and use multi-stage builds so compilers and dev dependencies never reach production layers. Most teams cut findings dramatically with those alone, before triaging anything by hand.
Does an image scan execute the container?
No. Scanning is static analysis of the unpacked filesystem and metadata — nothing in the image runs. That makes it safe to scan untrusted images, and it is also exactly why runtime misconfigurations are outside its sight.