You can ship an image that passes every test and still hand attackers a known way in. The application code might be fine, but the base image, the system libraries, and the language packages underneath it carry their own history of disclosed vulnerabilities. Most container CVEs come from those layers, not from code you wrote.
Docker Scout is Docker’s answer to this. It inventories everything inside an image, matches each package against published CVE advisories, and tells you what’s vulnerable, how bad it is, and whether a fix exists. It’s built into recent Docker Desktop, so for many people scanning is one command away.
This guide covers how Scout analyses an image, how to read the output, how to compare two images, and how to wire a scan into CI so vulnerable images don’t reach production.
What Docker Scout actually does
Scanning an image happens in two steps. First Scout builds an SBOM — a software bill of materials listing every package and version in the image, from the base OS packages up through your language dependencies. Then it matches that list against a continuously updated database of CVE advisories.
The result is a report: which packages are vulnerable, the severity of each issue, and whether a fixed version is available. Because the matching is based on what’s actually installed, it catches problems in layers you didn’t write — the OpenSSL version in your base image, a transitive npm dependency, an old system library.
What Scout reports
| SBOM | Every package and version found in the image, across all layers. |
|---|---|
| CVEs by severity | Critical / high / medium / low counts, matched from advisory data. |
| Fix availability | Whether a patched version of the affected package exists. |
| Base image guidance | Recommended base image updates that cut the CVE count. |
Your first scan: quickview
Start with quickview. It gives a one-screen summary of an image and its base image, which is enough to decide whether you need to look closer:
docker scout quickview node:22
Target │ node:22 │ 0C 2H 18M 34L
digest │ a1b2c3d4e5f6 │
Base image │ buildpack-deps:bookworm │ 0C 1H 11M 27L
Updated base image │ buildpack-deps:bookworm │ 0C 0H 4M 12L
The columns are counts by severity — Critical, High, Medium, Low. The first row is your image; the base image rows show how much of that risk comes from the base, and what an updated base would look like. If almost all your CVEs are in the base image, updating the base is the highest-leverage fix.
You can scan a local image you just built, by tag or ID, without pushing it anywhere:
docker build -t myapp:latest .
docker scout quickview myapp:latest
Digging in with the cves command
When quickview shows findings worth investigating, cves lists each one with the affected package, the installed version, the severity, and whether a fix is out:
docker scout cves myapp:latest
The output groups vulnerabilities by package and names the CVE IDs, the CVSS severity, and the version that fixes each issue. That last part matters most — a critical CVE with no fix available is a different decision from one where bumping a dependency by a patch version closes it.
You’ll usually want to filter. Show only what you can act on, or only what’s serious:
# Only CVEs that have a fix available
docker scout cves --only-fixed myapp:latest
# Only critical and high severity
docker scout cves --only-severity critical,high myapp:latest
# Focus on a single package
docker scout cves --only-package openssl myapp:latest
Getting fix recommendations
Scout doesn’t just flag problems — it suggests the most effective remediation, which is usually a base image change. The recommendations command analyses your image and proposes base images that reduce the vulnerability count while staying compatible:
docker scout recommendations myapp:latest
It might tell you that moving from a bookworm base to a newer minor tag clears several high-severity CVEs, or that a -slim variant removes vulnerable packages you don’t need. You still make the change in your Dockerfile and rebuild — Scout points the way, it doesn’t edit anything.
This pairs well with multi-stage builds: a smaller final base has fewer packages, which means fewer packages that can carry CVEs. Reducing the image’s footprint and reducing its vulnerability surface are often the same action.
Comparing two images
One of Scout’s most useful features is comparing images, so you can see whether a change actually improved things. The compare command diffs the vulnerabilities between two tags:
docker scout compare --to myapp:1.4.0 myapp:1.5.0
This answers the question you actually care about during a release: did this build introduce new CVEs, or fix some? It’s far more useful than scanning a single image in isolation, because it shows the direction of change. A common workflow is comparing your freshly built image against the version currently in production before you deploy.
Core Docker Scout commands
| docker scout quickview <image> | Fast severity summary for the image and its base. |
|---|---|
| docker scout cves <image> | Full per-CVE list with packages, severity, and fixes. |
| docker scout recommendations <image> | Suggested base image updates to cut CVEs. |
| docker scout compare --to <a> <b> | Diff vulnerabilities between two images. |
| docker scout sbom <image> | Output the software bill of materials for the image. |
Gating CI on vulnerabilities
Scanning by hand is fine for occasional checks, but the real value comes from running Scout automatically and failing the build when serious, fixable CVEs appear. The --exit-code flag makes cves return a non-zero status when matching vulnerabilities exist, which fails the CI step:
# Fail the pipeline if any fixable critical/high CVEs are present
docker scout cves --exit-code --only-severity critical,high --only-fixed myapp:latest
A minimal GitHub Actions step using that pattern:
- name: Scan image with Docker Scout
run: |
docker build -t myapp:${{ github.sha }} .
docker scout cves --exit-code --only-severity critical,high --only-fixed myapp:${{ github.sha }}
A scanning habit that scales
Working Docker Scout into your routine
- Run quickview on every image before you push it
- Use --only-fixed to focus on actionable CVEs first
- Check recommendations and update base images regularly
- compare new builds against the running version before deploying
- Gate CI on fixable critical/high CVEs with --exit-code
- Rescan deployed images periodically — new CVEs appear over time
That last item is easy to forget. An image you scanned clean last month can show new findings today without a single byte changing, because the CVE was only just disclosed. Scanning is not a one-time gate at build; it’s an ongoing check against a moving target.
Wrapping up
Docker Scout turns “is this image safe?” into a command you can actually run. Use quickview to triage, cves to see specifics, recommendations to find the base image that clears the most issues, and compare to confirm a build moved in the right direction. Then put cves --exit-code in CI so vulnerable images get caught before they ship, gating on the issues you can fix rather than every advisory in existence.
The biggest practical insight is that most of your container risk lives in the base image and dependencies, not your own code — so the cheapest security win is often a base image update Scout already suggested. Combine regular scanning with the broader security best practices and a smaller multi-stage image, and browse more in the Docker & Containers guides.