
Deep Dive: Container Image Scanning Explained — What Trivy, Grype, and Docker Scout Are Actually Checking
Scan the same image with Trivy, Grype, and Docker Scout and you'll get three different vulnerability counts — and all three tools are right.
That sentence sounds like a bug report. It isn't. Every "best container scanner" post online hands you an install command and stops there, as if the tools were interchangeable. They're not. Each one builds its view of what's inside your image differently, pulls CVE data from different places, and matches packages against that data with different rules. If you don't understand those three differences, you can't actually trust the number a scanner hands you in CI — you're just trusting a black box.
So instead of another install guide, here's what each tool is actually doing under the hood, followed by a real side-by-side run against the same deliberately outdated image so you can see the disagreement for yourself.
What Each Tool Actually Inspects
Trivy
Trivy (Aqua Security) walks the image's filesystem layer by layer and fingerprints what it finds: OS packages from the package manager database (apt/dpkg, apk, rpm), language-level dependencies it can detect directly in the filesystem (a requirements.txt, a package-lock.json, a Go binary's embedded module list, a Java .jar's manifest), known misconfiguration patterns, and exposed secrets if you enable that scanner. It checks all of that against its own aggregated vulnerability database, which pulls from multiple upstream sources — NVD, GitHub Security Advisories, and distro-specific advisories (Debian, Alpine's secdb, Red Hat's OVAL feeds) — and keeps its own cached copy that updates on a schedule.
The key thing: Trivy scans the filesystem directly. It doesn't need you to hand it an inventory first — it builds its own as it scans.
Grype
Grype (Anchore) works the opposite way: it's SBOM-first. Under the hood it calls Syft, Anchore's software bill-of-materials generator, to produce a structured inventory of every package in the image — name, version, type, location — and only then matches that inventory against Grype's own vulnerability database. If you already generate SBOMs as part of your pipeline (which more teams are required to do now for supply-chain compliance), Grype can consume that existing SBOM directly instead of regenerating one, which is its real advantage: one inventory, reusable across your scanning, compliance, and audit tooling.
Because it's matching against a structured SBOM rather than walking the filesystem itself, how precisely Syft identified a package's name and version determines how well Grype can match it to a CVE. Get the SBOM wrong — a mis-parsed version string, a package manager Syft doesn't fully support — and Grype will miss or misreport findings for it.
Docker Scout
Docker Scout ships as a CLI plugin bundled with modern Docker Desktop and the Docker CLI, which means it's the one most teams encounter first without installing anything extra. It also generates an SBOM-style inventory (built on its own indexing, not Syft), but its real differentiator is that it's integrated with Docker Hub and your registry: it can compare an image against upstream base-image recommendations, flag when a newer, less-vulnerable base image exists, and evaluate organization-defined policies (e.g. "block images with a critical CVE older than 30 days with a fix available") rather than just listing CVEs.
The Worked Example: Same Image, Three Scanners
Talk is cheap — let's point all three at the same target. For a deliberately outdated image, python:3.8-slim is a good pick: Python 3.8 is end-of-life, the base Debian layer underneath it hasn't been rebuilt in a long time for that tag, and it's common enough that you've probably got something like it sitting in a registry right now.
1. Install each tool
# Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin v0.54.1
# or: brew install trivy
# Grype
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
# or: brew install grype
# Docker Scout (bundled with recent Docker Desktop/CLI — verify first)
docker scout version || docker scout quickview --help2. Pull the test image
docker pull python:3.8-slim3. Run each scanner, same image, same severity filter
# Trivy — scans the filesystem directly, no SBOM step needed
trivy image --severity HIGH,CRITICAL python:3.8-slim
# Grype — generates an SBOM via Syft internally, then matches it
grype python:3.8-slim --only-fixed=false
# Docker Scout — uses its own inventory + Docker Hub's CVE data
docker scout cves python:3.8-slim --only-severity critical,high4. What you'll see — and why the counts won't match
This is illustrative, not a captured run — your actual numbers will depend on the day you run it, since every one of these databases updates continuously. But the shape of the disagreement looks like this every time:
- Trivy typically reports the highest count on OS-level packages, because its distro-advisory feeds (especially Debian's) tend to flag package versions as vulnerable even when no practical exploit path exists for that package in that context — it's optimizing for "tell me about everything," not "tell me what's exploitable."
- Grype often reports a different count for the exact same OS packages, because its matching logic applies its own confidence rules about whether a given version range in an advisory actually applies to the installed version string Syft extracted — a stricter or looser version-range match than Trivy's own logic produces a different list, not because one is "more correct," but because they implemented the matching heuristic differently.
- Docker Scout frequently reports the lowest raw count for the base layers specifically, because it cross-references against Docker Hub's own curated advisory data and will sometimes suppress findings already marked "not applicable" upstream for that specific official image build — but then it adds policy-level findings (like "a newer base image with 40% fewer known CVEs exists") that the other two don't surface at all.
Why the Numbers Diverge: The Real Reasons
Four mechanical reasons explain almost all of the gap, and knowing them is what lets you stop treating "which tool found more CVEs" as the metric that matters:
- Database freshness. Trivy, Grype, and Scout each maintain or query separate vulnerability databases on separate update cadences. A CVE published an hour ago might already be in one tool's feed and not yet synced into another's local cache. Run the same scan twice, a day apart, with no change to the image, and you can get a different count from the same tool — that's the database changing, not the image.
- Matching logic. "Is version 1.2.3 affected by a CVE whose advisory says '< 1.3.0'?" sounds like simple arithmetic, but distro package versioning schemes (Debian's epoch-and-revision format, Alpine's, RPM's) don't compare the same way semver does, and each scanner has written its own parser and comparison rules for each ecosystem. Edge cases in that parsing are where tools genuinely disagree on the same input.
- SBOM-based vs. direct filesystem scanning. Grype and Scout reason over a generated inventory; Trivy reasons over the filesystem directly (though it can also consume an SBOM). An inventory step adds a translation layer — great for reuse across tooling, but it's one more place a package can be missed, misnamed, or have its version misparsed before the vulnerability match even happens.
- Severity source and scoring. CVSS scores differ depending on who scored them — NVD's score for a CVE and a distro maintainer's own severity assessment for the same CVE are sometimes different numbers. If one tool defaults to NVD's score and another defaults to the distro's own advisory severity, the same CVE can land in "critical" in one tool's output and "medium" in another's.
So Which One Should You Actually Use?
Pick by what you need, not by which tool returns the biggest scary number:
- Need broad, fast, no-setup coverage in CI, including secrets and misconfig? Trivy. It's the one tool here that does all of that out of the box with a single binary and no SBOM step.
- Already generating SBOMs for compliance, or want one inventory reused across multiple security tools? Grype, paired with Syft — that pairing is designed to be the reusable inventory layer other tools build on.
- Living inside Docker Desktop day to day, and want base-image recommendations and policy gates, not just a CVE list? Docker Scout — it's the only one of the three that tells you what to switch to, not just what's wrong.
In practice, plenty of mature pipelines run more than one — Trivy in CI as the fast gate, Grype against the SBOM for the compliance trail. Disagreement between them isn't a sign something's broken; it's two different lenses on the same image, and now you know what each lens is actually built to see.
Follow for more deep dives like this one — next up, we're taking the same "what's actually happening under the hood" approach to SBOM diffing across image versions.

Experienced DevOps Engineer proficient in Python, Docker, Kubernetes, CI/CD, and cloud technologies. Specialized in automating processes and building scalable infrastructure for seamless development and deployment.


