- comparisons
- container scanning
- open source
Trivy vs Grype: which container vulnerability scanner to use, and where they disagree
Trivy scans more targets; Grype ranks by EPSS and KEV. On the same nginx image they reported 139 and 198 CVE IDs and agreed on 136. Why, and which to run where.
StackRadar Team
13 min read
Pick Trivy when you want one binary that scans images, filesystems, IaC, secrets and a Kubernetes cluster. Pick Grype when you want the best vulnerability matching and ranking for images and SBOMs, especially if you already generate SBOMs with Syft. Both are Apache-2.0, both are free, both are good. The differences that matter are what each one scans, how each one ranks, and how much they disagree on the same image, which is more than most comparisons admit.
This post runs both against the same image and reads the two reports side by side, then covers the flags you will actually use, the two things that went wrong for each project in 2026, and what either one can do inside a Kubernetes cluster.
The short answer, by job:
- One tool for everything in CI: Trivy.
- You generate SBOMs and want to re-scan them: Grype, with Syft.
- You want EPSS and KEV in the output: Grype.
- IaC, secrets, licences: Trivy. Grype does not do them.
- Inside a Kubernetes cluster: Trivy Operator. Grype has no equivalent.
- Across clusters, with history: neither; see the last section.
What each one is
Trivy (Aqua Security) is a general-purpose security scanner. Its targets are container images, filesystems, root filesystems, code repositories, virtual machine images, Kubernetes clusters and SBOMs. Its scanners are vuln, misconfig, secret and license, with vuln,secret on by default. The misconfiguration checks cover Terraform, CloudFormation, Helm, Kubernetes manifests, Dockerfiles, Ansible and ARM templates. The same engine runs inside the cluster as Trivy Operator.
Grype (Anchore) does one job: match packages against vulnerability data. It reads an image from a daemon, a registry, an OCI directory or a tarball, a directory on disk, a Syft or CycloneDX SBOM, or a plain list of package URLs or CPEs, and it returns matches. Its sibling Syft builds the inventory; Grype is built to consume it. Its database carries EPSS scores and the CISA KEV catalogue, it supports OpenVEX for suppressing and augmenting results, and its default sort order is a risk score rather than severity.
The same image, two different answers
We scanned docker.io/library/nginx:1.27-alpine for linux/amd64 with both on 30 October 2026, Trivy 0.76.1 against a fresh database and Grype 0.117.0 against database v6.1.10 built that morning.
# Trivy: pulls the image and its database, prints everything as JSON
trivy image -q -f json --platform linux/amd64 docker.io/library/nginx:1.27-alpine > trivy.json
# Grype: straight from the registry, no daemon
grype -q -o json --platform linux/amd64 registry:docker.io/library/nginx:1.27-alpine > grype.json
# or from an SBOM you already have (Syft, Trivy or anyone's CycloneDX)
grype -q -o json sbom:nginx.cdx.json| Trivy 0.76.1 | Grype 0.117.0 | |
|---|---|---|
| Packages inventoried | 68 | 68 |
| Findings (rows) | 212 | 271 |
| Distinct vulnerability IDs | 139 | 198 |
| IDs both report | 136 | |
| Findings with a fixed version | 212 (all of them) | 207 |
| Findings with no fix | 0 | 64 |
| Critical / High / Medium / Low / Unknown | 3 / 57 / 100 / 46 / 6 | 26 / 105 / 99 / 22 / 19 |
| Marked as in CISA KEV | not a field | 1 (CVE-2026-111497, brotli-libs) |
Same image, same 68 packages, and the two reports share 136 IDs. Then Grype adds 62 and Trivy adds 3. Reading the JSON explains most of it:
jq '[.Results[].Vulnerabilities // [] | length] | add' trivy.json # 212
jq '.matches | length' grype.json # 271
jq -r '.Results[].Vulnerabilities[].VulnerabilityID' trivy.json | sort -u | wc -l # 139
jq -r '.matches[].vulnerability.id' grype.json | sort -u | wc -l # 198
# where Grype's extra rows come from: the data source behind each unfixed match
jq -r '.matches[] | select(.vulnerability.fix.state != "fixed") | .vulnerability.namespace' grype.json \
| sort | uniq -c
# 64 nvd:cpe- Grype's 207 fixed matches all come from Alpine's security database (namespace
alpine:distro:alpine:3.21). Trivy uses the same source for Alpine packages. That is the overlap. - Grype's 64 unfixed matches all come from NVD, via CPE matching (namespace
nvd:cpe). Alpine's database lists only vulnerabilities it has fixed, so Trivy, which trusts the distro for OS packages, reports nothing Alpine has not listed. Grype also asks NVD whether anything is filed against each package's CPE. That surfaces real unpatched issues and also false positives, and it is why 60 of Grype's 271 rows are oncurl.--only-fixedor--ignore-states not-fixed,unknownbrings Grype within a few rows of Trivy. - Trivy's 3 extra IDs (CVE-2025-4947, CVE-2025-5025, CVE-2026-22184) are Alpine-listed fixes that Grype's database did not have that day. Two scanners built from the same upstream feed still lag each other by days.
- Severity is where they disagree most. Trivy calls 3 findings critical; Grype calls 26 matches critical, across 19 IDs. Of those 19, Trivy rates 2 critical, 4 high, 2 medium and 2 low, and does not report 9 at all. Each tool picks a different record to take the score from when the distro gives none. Do not gate a pipeline on a severity word and expect two scanners to agree.
- They agree on the one that matters. Both report CVE-2026-111497 in
brotli-libs1.1.0-r2, fixed in 1.1.1-r0, and both rate it critical. Only Grype tells you it is in CISA's Known Exploited Vulnerabilities catalogue. In Trivy's output it is one critical among three.
Ranking: severity, or exploitation
Grype's database (schema v6) stores an EPSS score and percentile and the KEV record alongside each advisory. Every match in its JSON carries epss, knownExploited and a risk score, and --sort-by accepts risk (the default), epss, kev, severity, package and vulnerability. Trivy ranks by severity and has no EPSS or KEV fields as of October 2026.
# Grype: exploitation data is in the database, so sorting needs no join
grype --sort-by kev nginx:1.27-alpine # KEV entries first
grype --sort-by epss nginx:1.27-alpine # by exploitation probability
grype -o json nginx:1.27-alpine | jq '.matches[].vulnerability | {id, epss, knownExploited, risk}'
# Trivy: severity only; join EPSS and KEV yourself (see the prioritisation post)
trivy image --severity HIGH,CRITICAL nginx:1.27-alpineOn a real image this is the difference between a list of 271 rows and a list of 12. How to prioritise container vulnerabilities with EPSS and KEV shows the tiers, and includes a script that does the join for Trivy JSON when you cannot switch scanners.
The flags you will actually use
| Task | Trivy | Grype |
|---|---|---|
| Only findings with a fix | --ignore-unfixed | --only-fixed, or --ignore-states not-fixed,wont-fix,unknown |
| Fail the pipeline | --exit-code 1 --severity HIGH,CRITICAL | --fail-on high (exits 2) |
| Sort by exploitation | not available | --sort-by kev, epss or risk |
| Scan an SBOM | trivy sbom bom.cdx.json | grype sbom:bom.cdx.json |
| Report the CVE rather than the source's ID | reports whichever ID the source uses | --by-cve |
| Apply VEX statements | --vex repo, oci or a file (experimental) | --vex statements.openvex.json |
| Match the nodes, not the laptop | --platform linux/amd64 | --platform linux/amd64 |
| Trade recall for precision | --detection-priority precise (default) or comprehensive | CPE matching on or off per ecosystem in .grype.yaml |
| Database control | --skip-db-update; --db-repository for a mirror | grype db status, grype db update; GRYPE_DB_AUTO_UPDATE=false |
| Output formats | table, json, template, sarif, cyclonedx, spdx, spdx-json, github, cosign-vuln | table, json, cyclonedx, cyclonedx-json, sarif, template |
| Misconfigurations, secrets, licences | --scanners vuln,misconfig,secret,license | not supported |
Two things that happened in 2026, and what they mean for you
Trivy's release channel was compromised. Between 19 and 23 March 2026 a threat actor used a compromised credential to publish malicious Trivy release binaries, images and trivy-action tags (GHSA-69fq-xp46-6x23). The project recovered quickly and the lesson is not specific to Trivy: pin the scanner you run in CI by digest or checksum, not by a floating tag, and verify the signature. A vulnerability scanner runs with your registry credentials.
Grype's old database schema reached end of life. On 6 March 2026 Anchore stopped publishing updates for DB schema v5. Any Grype older than v0.88.0 kept running and kept passing, against a database frozen in March. The announcement's only instruction is to upgrade to v0.88.0 or later; the lesson is that a pinned scanner needs its pin moved on a schedule, and grype db status (or Trivy's Metadata block) belongs in your CI log so a stale database is visible.
In a Kubernetes cluster
Trivy has two answers. trivy k8s scans a cluster from outside, through your kubeconfig, and can write a cluster-level SBOM; it is marked experimental. Trivy Operator runs inside the cluster, scans each workload as it appears and stores the result as a custom resource, with the storage cost described in Trivy Operator without the etcd problem. Grype has no cluster mode at all: the pattern is to list the digests the kubelets are running, generate one SBOM per digest with Syft, and run Grype over the SBOMs, which this post scripts.
# Trivy: one-shot cluster scan from your laptop (experimental), or a KBOM
trivy k8s --report summary
trivy k8s --scanners vuln --report all
trivy k8s --format cyclonedx --output cluster.cdx.json
# Grype has no cluster mode: list running digests, SBOM each, scan each
grype sbom:sboms/9f2c.cdx.json -o jsonBoth approaches are one scan at a time. Neither re-ranks yesterday's findings when EPSS moves or KEV adds an entry, neither keeps a history, and neither spans clusters. Open-source vulnerability scanners for Kubernetes covers what each leaves for you to build. The free StackRadar CLI is a third opinion in the same shape as trivy k8s: it lists every running digest, scans each against OSV and flags KEV entries, from your laptop, with no agent. StackRadar itself is the continuous version: one SBOM per running image, re-matched as advisories land, across every cluster, with the history kept outside etcd.
Which one to run
- Choose Trivy if you want one binary for images, IaC, secrets and licences, if you run Trivy Operator or plan to, or if your platform team has standardised on it. Pin it by digest.
- Choose Grype if your pipeline already produces SBOMs, if you want EPSS and KEV in the output without a script, or if you want to re-scan stored SBOMs nightly instead of pulling images. Keep it on a current release.
- Run both on a sample of images once. The disagreement is the useful part: a finding that only one reports is the one worth a minute of reading.
Frequently asked questions
Is Grype better than Trivy?
At matching packages to vulnerabilities and ranking the result, Grype has the edge: its database carries EPSS scores and KEV membership, its default sort is a risk score built from them, and it reads SBOMs natively through Syft. At everything else, Trivy wins by doing it at all: misconfigurations, secrets, licences, IaC, VM images, a Kubernetes cluster and an in-cluster operator. Pick by the job, not by the name.
Why do Trivy and Grype report different vulnerabilities on the same image?
On nginx:1.27-alpine they agreed on 136 IDs, then Grype added 62 and Trivy added 3. Grype’s extras all came from matching package CPEs against NVD records (its nvd:cpe namespace), which finds issues the distro has not triaged, including unfixed ones and some false positives. Trivy trusts the distro’s security database for OS packages, and Alpine’s lists only fixed vulnerabilities. Severities differ too, because each tool picks a different record to take the score from.
Does Trivy show EPSS or KEV?
Not as of October 2026. Trivy’s JSON has severity, CVSS vectors from several sources and a fix status, but no EPSS score and no KEV flag. Grype’s JSON carries an epss array, a knownExploited array and a risk score on every match, and --sort-by accepts risk, epss, kev and severity. For Trivy, a short script joining the two public feeds does the same job.
Can Grype scan Infrastructure as Code, secrets or licences?
No. Grype does one thing: match the packages in an image, directory or SBOM against vulnerability data. Trivy’s --scanners flag takes vuln, misconfig, secret and license, and its misconfiguration checks cover Terraform, CloudFormation, Helm, Kubernetes manifests, Dockerfiles, Ansible and ARM templates.
Which is faster, Trivy or Grype?
Neither is the bottleneck. On this image both finished well inside a minute once their databases were cached; the first run of either downloads a database measured in hundreds of megabytes, which dominates. Benchmarks that show one scanner 30% faster than the other are measuring the wrong thing for a CI job that also builds and pushes the image.
Can I use a Trivy SBOM with Grype, or a Syft SBOM with Trivy?
Yes, in both directions, through CycloneDX. `trivy image --format cyclonedx` produces a document that `grype sbom:file.cdx.json` reads, and `syft -o cyclonedx-json` produces one that `trivy sbom file.cdx.json` reads. Expect the match counts to differ from scanning the image directly, because each scanner prefers its own inventory’s detail.
More from the blog
All postsWiz alternatives for small teams: what you actually need from a CNAPP when you run a handful of Kubernetes clusters
Small teams rarely need all of Wiz. Split it into five jobs and cover each with a cloud-native service or open-source tool for a fraction of $24,000 a year.
11 min read
Open-source Snyk Container alternatives: one tool per job, and what you give up
There is no single open-source Snyk Container, but every job it does has an open-source tool: Trivy, Grype, Renovate, Harbor, Trivy Operator and Dependency-Track.
10 min read
Self-hosted vulnerability management for Kubernetes: the open-source options, and what each one makes you run
Self-hosted vulnerability management: Trivy Operator, Kubescape, Harbor, Dependency-Track, DefectDojo, a CronJob or StackRadar CE, and what each makes you run.
12 min read
Container vulnerability scanning tools in 2026, by job
Container vulnerability scanning tools sorted by job: Trivy, Grype, Docker Scout and Snyk for an image in CI or a registry, and what scans a running cluster.
9 min read