Container Vulnerability Scanning: Trivy vs Grype vs Snyk
A practitioner's comparison of Trivy, Grype, and Snyk for finding CVEs in container images, plus how to wire scanning into CI without drowning in noise.
Key takeaways
A practitioner's comparison of Trivy, Grype, and Snyk for finding CVEs in container images, plus how to wire scanning into CI without drowning in noise.
On this page
Container Vulnerability Scanning: Trivy vs Grype vs Snyk#
A container image is not a single thing you audited once. It is a stack of other people's decisions: a base image someone else built, an OS package tree that shipped with it, and the language dependencies your app pulled in at build time. Every one of those layers accumulates CVEs over time, and the clock never stops. An image that scanned clean in March is full of new findings by July, not because anything in it changed, but because the world learned more about what was already there.
That is why container vulnerability scanning is a continuous job, not a gate you pass once. This post covers what scanners check, compares the tools people reach for, and shows how to wire scanning into CI without burying your team in noise.
Why images pile up CVEs#
Three sources feed the pile:
Base image: If you start from ubuntu:22.04 or node:20, you inherit hundreds of installed packages you never chose. Most are fine. Some carry known vulnerabilities the moment you pull them.
OS packages: apt, apk, and yum install shared libraries (openssl, glibc, zlib, curl) that get CVEs disclosed against them constantly. Your Dockerfile might not touch them, but they are in the image and part of your attack surface.
Application dependencies: The npm, pip, go, and Maven packages your code imports, plus their transitive dependencies. This overlaps heavily with dependency and SCA scanning, and good container scanners cover it too.
What scanners actually check#
The better tools go well past "list the CVEs." A full scan covers:
- OS packages: cross-reference installed package versions against vulnerability databases (NVD, distro security trackers, GitHub Advisories).
- Language dependencies: parse lockfiles and installed modules for known-vulnerable versions.
- Misconfiguration: Dockerfile and IaC checks (running as root, no
USERdirective, world-writable files). - Secrets: hardcoded API keys, tokens, and private keys baked into a layer.
- Licenses: flag GPL or other licenses that violate your policy.
Not every tool does all five, and that spread is most of the difference between them.
The tools#
Trivy (Aqua Security)#
Open source, fast, and broad. Trivy scans OS packages, language deps, IaC, secrets, and licenses in one binary with no server to run. It has become the default in most CI pipelines because it is trivial to install and covers the widest surface for free. A basic scan:
$ trivy image myapp:1.4.2
myapp:1.4.2 (debian 12.4)
Total: 14 (HIGH: 11, CRITICAL: 3)
┌────────────┬────────────────┬──────────┬────────────┬───────────────┬──────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Installed Ver │ Fixed Version │
├────────────┼────────────────┼──────────┼────────────┼───────────────┼──────────────────────┤
│ libssl3 │ CVE-2024-6119 │ HIGH │ fixed │ 3.0.11-1 │ 3.0.13-1~deb12u1 │
│ zlib1g │ CVE-2023-45853 │ CRITICAL │ affected │ 1:1.2.13-1 │ │
│ libcurl4 │ CVE-2024-2004 │ HIGH │ fixed │ 7.88.1-10 │ 7.88.1-10+deb12u5 │
└────────────┴────────────────┴──────────┴────────────┴───────────────┴──────────────────────┘
Note the Status column. fixed means an upgrade exists; affected means the CVE is real but no patched version has shipped yet. That distinction drives triage.
Grype (Anchore)#
Also open source, and built around SBOMs. Grype pairs with Syft (Anchore's SBOM generator): you produce a software bill of materials once, then scan it repeatedly without re-cracking the image. If you already generate SBOMs for supply-chain security with SBOMs, Grype fits that flow naturally. Detection quality is close to Trivy's for OS and language packages, though it does less on misconfig and secrets.
Snyk#
Commercial, and the most developer-focused of the three. Snyk's edge is fix advice: it tells you the exact base-image bump or dependency upgrade that clears the most CVEs, and it integrates into IDEs, PRs, and its own dashboard. You pay for that polish, plus curated vulnerability data that sometimes flags issues before public databases catch up. For teams that want managed data and guided remediation rather than raw findings, it earns its price.
The rest#
Docker Scout: built into Docker Desktop and Docker Hub, convenient if you live in that ecosystem, with decent base-image recommendations.
Clair: the older open-source engine behind several registries; powerful but heavier to operate standalone.
Registry-native scanning: ECR, GCR/Artifact Registry, and ACR all scan images on push automatically. A great safety net because it runs whether or not your CI did, but a backstop, not a substitute for shifting the check left into the build.
The workflow that actually works#
Scanning is only useful if it changes what ships. The pattern:
Fail the build on HIGH/CRITICAL. Run the scan in CI and exit non-zero when severe, fixable findings appear. Here is a GitHub Actions step using Trivy:
- name: Scan image for vulnerabilities
uses: aquasecurity/trivy-action@0.24.0
with:
image-ref: myapp:${{ github.sha }}
format: table
exit-code: '1' # fail the job on a match
severity: HIGH,CRITICAL
ignore-unfixed: true # only block on CVEs that have a fix
ignore-unfixed: true is the pragmatic setting. Blocking on a CRITICAL with no available patch just stops your pipeline over something you cannot act on. Track those separately.
Scan and pin the base image. Pin by digest, not a floating tag, and rebuild on a schedule so base-image patches actually reach production.
Shrink the surface. Distroless or minimal bases (gcr.io/distroless, alpine, chainguard) remove the shells, package managers, and libraries you never use. Fewer packages means fewer CVEs by definition, and it is the single highest-leverage change most teams can make.
Generate an SBOM. Produce one at build time so you can answer "are we affected by the next Log4Shell?" in minutes instead of days.
Admission control. Use an admission controller (Kyverno, OPA Gatekeeper, or your registry's signing policy) to block images that were never scanned or signed from running in the cluster.
The noise problem#
Point a scanner at a real image and you will get dozens of findings. Most are not actionable, and treating them as equal is how teams learn to ignore the scanner entirely. Prioritize by three signals together:
- Severity: CRITICAL and HIGH first, but severity alone is a weak filter.
- Fix available: a CVE with a patched version is work you can finish today. One without is a note to watch.
- Reachability: is the vulnerable code path actually invoked? A CVE in a library your app links but never calls is far lower risk than one in your request-handling hot path. Tools with reachability analysis (Snyk, and increasingly others) cut the list dramatically.
The goal is a short queue of "severe, fixable, reachable" items your team actually clears, not a 400-row report nobody reads. This mindset lines up with the broader application security best practices: reduce input, reduce surface, and act on what is exploitable rather than what merely exists.
How to choose#
- You want one free tool covering the most ground: Trivy. Fast, broad, no infrastructure.
- You already build SBOMs and want scanning to slot into that pipeline: Grype plus Syft.
- You want managed data, IDE/PR integration, and guided fixes, and can pay: Snyk.
- You live in Docker's ecosystem and want zero setup: Docker Scout as a first pass.
- Regardless of the above: turn on registry-native scanning as a backstop.
The call we'd make#
Start with Trivy in CI, failing the build on HIGH/CRITICAL with ignore-unfixed on, and pair it with distroless base images to cut the finding count at the source. Turn on your registry's native scanning as a second layer, and add admission control so nothing unscanned reaches the cluster. If your organization can fund it and remediation speed matters more than tooling cost, add Snyk on top for its fix advice and reachability data. The tool choice matters less than the discipline around it: scan continuously, fail on what is fixable, shrink the image, and keep the queue short enough that people trust it.
Get the DevOps Troubleshooting Cheat Sheet
Subscribe and get our free one-page reference for the errors that eat an afternoon — CrashLoopBackOff, OOMKilled, Terraform state locks, and more — plus new guides as we publish them.
Cilium vs Istio: eBPF Service Mesh Compared (2026)
A practitioner's comparison of Cilium's eBPF, sidecar-less dataplane against Istio's Envoy sidecar and ambient mesh models.
How to Detect and Fix Terraform Drift
Drift happens when real infrastructure diverges from your Terraform config, and here is how to spot it and put it back in sync.
More from DevOps
Explore more articles in this category
Best Managed Kubernetes in 2026: EKS vs GKE vs AKS vs DOKS
The control plane fee is the least interesting number. What separates managed Kubernetes providers is upgrade cadence, how much they run for you, and where the node bill lands.
Best Log Management Tools in 2026: What You Actually Pay For
Every log platform looks affordable at proof-of-concept volume and expensive at production volume. The pricing model, not the feature list, decides which one you can live with.
Your CI Runner Is the Target: Hardening Against npm Worms
The keyv compromise reached 444 packages and over two billion monthly installs through preinstall scripts. The controls that actually stop it are boring and mostly free.
You might have missed
Evergreen posts worth revisiting.