Home/Tool Reviews/Trivy vs Grype: A Practical Guide to Choosing a Container Vulnerability Scanner
Tool ReviewsTrivyGrype

Trivy vs Grype: A Practical Guide to Choosing a Container Vulnerability Scanner

If you're stuck choosing between Trivy and Grype, decide on three things: DB source, false-positive handling, and CI fail policy. This practical guide covers CI integration examples, SBOM workflows, and recommendations by situation.

Trivy vs Grype: A Practical Guide to Choosing a Container Vulnerability Scanner
Contents
  1. Why you should put a vulnerability scanner in CI now
  2. 5-minute hands-on: install and first scan
  3. Head-to-head comparison
  4. Wiring it into CI: fail the build + ignore false positives
  5. SBOM workflow differences
  6. Choose by situation
  7. FAQ

Trivy vs Grype: A Practical Guide to Choosing a Container Vulnerability Scanner

Let's start with the conclusion. Choose Trivy if you want one tool that also covers IaC, secrets, and Kubernetes. Choose Grype if your pipeline is SBOM-centric, you already use syft, or you need fine-grained ignore rules. Both are free and open source with similar GitHub stars, which is why picking one feels so hard—but the real differentiators aren't stars. They're DB source, false-positive handling, and CI fail policy. Use this post to decide in five minutes and ship it the same day with copy-paste CI snippets.

Why you should put a vulnerability scanner in CI now

SBOM submission is becoming de facto mandatory under U.S. Executive Order 14028 and the EU Cyber Resilience Act (CRA). The core of DevSecOps is "shift-left"—moving security checks from runtime into the build. Blocking CRITICAL vulnerabilities before an image hits the registry and before a PR is merged is now the standard. Trivy and Grype are the two leading open-source scanners competing for that slot.

5-minute hands-on: install and first scan

Run both against the same image (python:3.12-slim) and you'll feel the differences immediately.

Bash
# Trivy (Aqua Security)
brew install trivy
trivy image python:3.12-slim

# Grype (Anchore)
brew install grype
# or: curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
grype python:3.12-slim

The first run takes tens of seconds for both because they download the vulnerability DB; after that, cache makes subsequent scans finish in a few seconds. The output columns are similar too.

  • Trivy: Library(package) / Vulnerability(CVE-ID) / Severity / Installed Version / Fixed Version / Title
  • Grype: NAME(package) / INSTALLED(installed version) / FIXED-IN(fixed version) / TYPE / VULNERABILITY(CVE-ID) / SEVERITY

The point is that both tell you which package, which version, which CVE, and which version to upgrade to. Getting different result counts on the same image is normal—that's because of the DB source differences in the table below.

Head-to-head comparison

ItemTrivyGrype
Vendor / orgAqua SecurityAnchore
Vulnerability DBTrivy DB (Aqua-curated, distributed as OCI artifacts on GitHub)grype-db (NVD, GitHub Security Advisory, and distro security feeds combined)
First-run speedSeconds after DB downloadSeconds after DB download (similar)
Speed after cacheFastFast (Grype is usually a bit faster)
Scan targetsImages, filesystems, Git repos, IaC (Terraform, etc.), secrets, k8sImages, filesystems, SBOM-centric
SBOM generationBuilt-in (--format cyclonedx/spdx)Via companion tool syft
Ignore false positives.trivyignoreignore: block in .grype.yaml
LicenseApache 2.0 / freeApache 2.0 / free

Why the result counts differ: Trivy uses Aqua's processed and aggregated DB; Grype uses Anchore's DB that merges NVD with each distro's security feeds. Even for the same CVE, package matching rules and severity classification can differ, so counts diverge. Neither is "wrong"—they just have different data-source policies.

Wiring it into CI: fail the build + ignore false positives

GitHub Actions (Trivy)

YAML
- name: Trivy scan
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: 'myorg/myapp:${{ github.sha }}'
    severity: 'CRITICAL,HIGH'
 exit-code: '1' # CRITICAL/HIGH when 1 → failed → PR

GitLab CI (Trivy)

YAML
scan:
  script:
    - trivy image --exit-code 1 --severity CRITICAL,HIGH $IMAGE

Grype

Bash
grype myorg/myapp:latest --fail-on high
# high (= high, critical) when exit-code 1

exit-code 1 is the key. When the CI job fails, branch protection blocks the PR merge, so developers upgrade the vulnerable package before merge. That's shift-left in practice.

Conditional suppression of false positives

Instead of blanket suppression, conditional suppression plus an expiry date is the operational best practice. The most dangerous thing is turning something off and forgetting about it.

TEXT
# .trivyignore — CVE , expiry set
CVE-2023-12345 exp:2026-12-31
YAML
# .grype.yaml — vulnerability/package/fix-state when
ignore:
  - vulnerability: CVE-2023-12345
  - package:
      name: openssl
 fix-state: not-fixed # when when

Practical tip: I exclude "not-fixed" CVEs (no patched version yet) from build-breaking and track them in a separate backlog. If you break the build on things the team can't fix, they'll just turn the scanner off. That's where Grype's fix-state condition shines.

SBOM workflow differences

Grype pairs naturally with syft, which is also from Anchore.

Bash
syft myorg/myapp:latest -o syft-json | grype
# or SBOM
grype sbom:./sbom.json

Trivy can generate an SBOM on its own, without an extra tool, and rescan that SBOM.

Bash
trivy image --format cyclonedx -o sbom.json python:3.12-slim
trivy sbom sbom.json

Both cover SPDX and CycloneDX. The difference is whether you generate the SBOM with one tool (Trivy) or pipe a syft-generated SBOM straight through (Grype + syft). If you already have a syft pipeline, Grype feels natural. If you don't want another SBOM tool, Trivy alone is enough.

Choose by situation

Your situationRecommendation
All-in-one for images plus IaC, secrets, and k8s manifestsTrivy
Minimize learning curve, get started fastTrivy (friendly defaults)
SBOM-centric pipeline, already using syftGrype
Need fine-grained conditional ignore (fix-state, etc.)Grype
Start light with a single binaryEither works

FAQ

Q. Why do Trivy and Grype report different result counts? A. Because their vulnerability DB sources differ. Trivy uses Aqua's own aggregated DB; Grype uses grype-db, which combines NVD, GitHub Advisory, and distro feeds. Package matching rules and severity classification also differ, so counts diverge. Neither is wrong.

Q. Are both free? Are there commercial versions? A. Both are free under Apache 2.0. Aqua and Anchore also sell commercial platforms with policy management, reporting, and SLAs. For CI scanning, the free versions are enough.

Q. Which severity should we start failing CI on? A. Start by failing the build on CRITICAL only, then expand to HIGH once things stabilize. If you block on MEDIUM and below from day one, false positives and unfixed CVEs will break builds so often that the team will disable the scanner.

Q. Can we scan images without an SBOM? A. Yes. trivy image or grype <image> is enough to catch vulnerabilities. Add SBOM when you need supply-chain tracking, regulatory compliance, or automated rescan.

Q. We have too many false positives. How do we cut them down? A. Use conditional suppression, not blanket ignore. In Trivy, add an expiry (exp:) in .trivyignore. In Grype, temporarily exclude only items with fix-state: not-fixed in .grype.yaml. Always track ignored items in a backlog.

✦ ✦ ✦
Sources and verification

Sources and checks vary by article. Only articles with a recorded check date, scope and sources below were checked, and only within that scope. For other articles, verify against the current docs for your version before applying anything, and email us about errors. Editorial policy · email us

This article has no recorded human check (date and scope) yet.

Published ·
Topic-related official docs (auto-linked · not per-claim sources)Docker documentation ↗OWASP documentation ↗CISA SBOM ↗

Comments

Be the first to comment.