Trivy vs Grype for Vulnerability Scanning

Point Trivy and Grype at the same image and they will hand you different numbers. Neither is broken. They are reading overlapping-but-not-identical data through different lenses, and if you only run one you are trusting one lens.

Both are open-source, both scan container images for known vulnerabilities, and both are fast enough to sit in a pull-request gate. That is where the similarity ends. Trivy, from Aqua Security, is a broad scanner: OS packages, language dependencies, secrets, infrastructure-as-code misconfiguration, and licences, all from one binary. Grype, from Anchore, is a focused vulnerability matcher built around software bills of materials produced by its sibling tool, Syft. The difference in design shows up in the output, and it decides which one belongs where in your pipeline.

Running both on the same image

Here is the honest starting point: two commands, one image, and a comparison you can reproduce in a minute. Both tools download their database on first run and cache it, so the first scan is slower than the steady state.

Free · 4 minutes

Would you survive contact with a determined attacker — or an auditor?

Fourteen questions on access, patching, detection, and recovery — the basics that prevent most real incidents, and the ones most often assumed rather than verified. Banded finding on screen, full sheet by email.

# Trivy: OS + language packages, table output.
# By default Trivy also runs the secret scanner (--scanners vuln,secret).
trivy image --severity HIGH,CRITICAL python:3.12-slim

# Grype: same image, same intent.
grype python:3.12-slim

# Grype orients results by its own vuln ID; add --by-cve to align on CVEs,
# and --only-fixed to drop noise you can't action yet.
grype python:3.12-slim --by-cve --only-fixed

Run those and two things become obvious. The counts differ, and the way each presents the fixable-versus-unfixable split differs. That split is the single most useful column in either tool, so it is worth dwelling on.

The fixable split is the number that matters

A vulnerability with no available fix is not the same problem as one with a patched version waiting in the registry. The first is a risk you accept, mitigate, or wait out. The second is a task. Conflate them and your dashboard turns red permanently, everyone stops reading it, and the scanner becomes theatre.

Both tools let you filter to the actionable set. Trivy uses --ignore-unfixed; Grype uses --only-fixed. Same idea, opposite naming. In practice I gate the build on fixable findings only and report the rest separately, so the pipeline blocks on things a developer can actually resolve.

# Trivy: fail the build (exit 1) only on fixable HIGH/CRITICAL.
trivy image \
  --severity HIGH,CRITICAL \
  --ignore-unfixed \
  --exit-code 1 \
  ghcr.io/acme/api:latest

# Grype: --fail-on returns exit code 2 at or above the given severity.
# Combine with --only-fixed to gate on actionable findings.
grype ghcr.io/acme/api:latest \
  --only-fixed \
  --fail-on high

Note the exit codes differ: Trivy returns whatever you set with --exit-code, Grype returns 2 on a --fail-on trigger. If you script around them, do not assume they behave the same way. This is the same class of small, load-bearing detail that makes a difference in a pre-commit and CI baseline — the gate is only as good as the exit code it keys off.

Where each one genuinely wins

Trivy wins on breadth. One binary scans the image for CVEs, then also finds hardcoded secrets, flags Dockerfile and Kubernetes misconfigurations, and reads Terraform. If you want a single tool covering the messy reality of a repository — not just the built image but the code that builds it — Trivy carries more of the load. That breadth is why it is often the default in a fresh pipeline.

Grype wins on the SBOM workflow. Because Grype is built to consume an SBOM, you can generate the bill of materials once with Syft and scan it repeatedly — offline, in an air-gapped environment, or every time a new CVE lands without rebuilding the image. That separation of “what is in this artefact” from “what is wrong with it today” is architecturally cleaner, and it matters when you need to answer a supervisor’s question about an image you shipped three months ago.

# Generate the SBOM once with Syft, in CycloneDX JSON.
syft ghcr.io/acme/api:latest -o cyclonedx-json > api.sbom.json

# Re-scan the stored SBOM whenever the vuln database updates -
# no rebuild, no pull, works offline after 'grype db update'.
grype sbom:./api.sbom.json --only-fixed

# Trivy consumes the same SBOM too, if you prefer one toolchain.
trivy sbom ./api.sbom.json --severity HIGH,CRITICAL

Why the counts disagree

The disagreement is not random. The two tools draw on overlapping but distinct data — distribution security feeds, the GitHub Advisory Database, the NVD — and they reconcile it differently. They match packages to advisories using different logic, so one may report a CVE the other suppresses, and each occasionally produces a false positive the other avoids. This is why running both, at least periodically, catches gaps that either alone would miss.

I do not run both on every commit — that is cost without much marginal signal. I standardise on one in the fast inner loop and run the other on a schedule, weekly, against the same set of production images. When they diverge sharply on an image I ship, that divergence is itself a finding worth ten minutes of a human’s attention. Treat the second scanner as an audit of the first, not a duplicate of it.

What I standardised on, and why

For the CI gate I default to Trivy, because one tool covering vulnerabilities, secrets and IaC misconfiguration is less to maintain and less to explain to a team than three. For the artefact-provenance side — the SBOM you keep, re-scan and hand to an auditor — I use Syft and Grype, because that is the workflow they were designed for. The two are not rivals in my pipeline; they occupy different jobs, and the weekly cross-check between them is where the real assurance comes from.

Whichever you pick, wire the exit code into the pipeline so a fixable HIGH actually blocks a merge, feed the block rate into your change-failure and delivery metrics so the gate is visible rather than folkloric, and keep the same discipline you would apply to any security control — verify the thing you think you are verifying. A scanner that reports zero because it silently failed to download its database is worse than no scanner, because it tells you a comforting lie. Fail the build when the database is stale, not just when a CVE is found.

Free interactive tool

Website compliance checklist

What your site has to do, based on what it actually does

Answer as much or as little as you like — the list builds as you go. Nothing is stored against your name and no email is required.

Most technology problems are not technology problems. They are control problems.

The systems exist. The investment has been made. The question is whether leadership can understand, direct, evidence, and sustain what those systems produce. Find out where control exists — and where it only appears to.