How do you scan a Docker image for known vulnerabilities?

7 minadvancedvulnerability-scanningimage-securitycve

Quick Answer

Vulnerability scanners — Docker Scout, Trivy, Grype, or a registry's built-in scanning — inspect an image's layers to list every installed package and its version. They cross-reference that list against databases of known vulnerabilities (CVEs) to report which packages have disclosed security issues. Scanning should happen both in CI (blocking a build/deploy if severe issues are found) and on an ongoing basis for already-deployed images, since new vulnerabilities are discovered continuously in software that hasn't changed at all.

Detailed Answer

How scanning actually works

docker scout cves myapp:1.0
# or
trivy image myapp:1.0

A scanner inspects an image's layers to build an inventory of every installed package and its exact version — OS-level packages via the package manager's metadata, plus language-level dependencies like npm packages, Python packages, or Go modules, depending on the scanner. It then cross-references this inventory against vulnerability databases (like the National Vulnerability Database and vendor advisories) to report which packages have known, disclosed vulnerabilities (CVEs), each with a severity rating: critical, high, medium, or low.

myapp:1.0
Total: 12 vulnerabilities found

CRITICAL: 1
  - CVE-2023-XXXXX in openssl 1.1.1k (fixed in 1.1.1t)
HIGH: 3
  - CVE-2022-YYYYY in libcurl 7.68.0 (fixed in 7.74.0)
  ...

Why images need to be scanned repeatedly, not just once

A vulnerability report for an image can change without the image itself changing at all. A new CVE disclosed today might affect a package version that's been sitting unchanged inside an already-deployed image for months. Scanning shouldn't be a one-time gate at build time. Periodically re-scanning already-deployed images against the updated vulnerability database catches newly disclosed issues in software you already shipped and forgot about.

Integrating scanning into CI/CD

# Simplified CI pipeline step concept
- name: Scan image for vulnerabilities
  run: trivy image --exit-code 1 --severity CRITICAL,HIGH myapp:${{ github.sha }}

A common practice is failing the CI build with --exit-code 1 if the scan finds vulnerabilities at or above a chosen severity. This stops a dangerous image from ever reaching a registry or production, catching the problem as early as possible — often called "shifting left."

What to actually do about a finding

Most findings resolve one of a few ways:

  • Update the base image. Often the highest-leverage fix, since a newer base image tag frequently already includes patched versions of many packages.
  • Update the specific affected dependency, if it's pinned to an outdated version in your own dependency manifest.
  • Document and accept the risk, with a tracked exception, for the rare case where a fix isn't available yet and the vulnerable code path genuinely isn't reachable in your usage. Don't just silently ignore it.

Reducing the attack surface in the first place

Scanning detects problems — it doesn't prevent them. Pairing it with other practices reduces how much there is to find. Smaller base images, like Alpine or distroless, simply contain fewer packages. Multi-stage builds exclude build-time-only tooling from the final image. Both shrink the surface a scanner has to report on.

Registry-integrated scanning

Many registries — Docker Hub's paid tiers, GitHub Container Registry, AWS ECR, Harbor — offer built-in scanning that runs automatically on every push, with results in the registry's UI or API. This is convenient for centralizing scan results without a separate CI step. Standalone tools like Trivy stay popular because they run identically in any CI system or locally on a developer's machine, regardless of registry.

Related Resources