Trivy and Grype a Year Later: Which Matured Better

Trivy and Grype have been sitting as the two reference open-source container scanners for a couple of years now. Trivy comes from Aqua Security, Grype from Anchore, and although on paper they do the same thing —read Docker image layers, enumerate packages, cross-reference against CVE databases— in practice they’ve drifted toward different philosophies. After a long year running both in real CI pipelines, on images ranging from bare node:20 to Python bases with a hundred transitive dependencies, it’s pretty clear where each one wins.

Common Surface

What they share is easy to list: container image scanning, SBOM generation in SPDX and CycloneDX, GitHub Actions and GitLab CI integration, useful exit codes for breaking builds, Apache 2.0 licensing, and offline mode for air-gapped environments. If the requirement is just “we want a CVE scanner in the pipeline before publishing the image,” both do it and that’s that. The interesting discussion starts when scope grows.

Trivy: The Scanner That Became a Swiss Army Knife

Trivy started as an image scanner, but Aqua kept expanding the target until it covered filesystems, Git repos, Kubernetes manifests, Helm charts, Terraform modules and CloudFormation templates. The typical invocation boils down to four verbs —image, fs, config, repo— and all accept the same severity, output format and exit-code flags. That uniformity is what you appreciate most when wiring it into a pipeline: a single binary covers everything from “scan this image” to “review the Dockerfile and manifests that deploy it.”

The Kubernetes operator (Trivy Operator) is the other strong differentiator. Installed via Helm, it watches the cluster and generates four types of Custom Resources: VulnerabilityReports per pod, ConfigAuditReports with CIS Benchmark checks against live manifests, RbacAssessmentReports with RBAC issues and ExposedSecretReports that catch credentials baked into images. Everything lives as native Kubernetes resources, queryable via kubectl get and exportable to Prometheus. For a team already deep in the K8s ecosystem, that’s what tips the balance.

Grype: Narrow Focus, Clean Finish

Grype does fewer things but with more polished ergonomics. It accepts an image, a directory, or an SBOM previously generated by Syft, and returns a list of CVEs without trying to opine on IaC or misconfigurations. The Syft integration is the key: Syft generates the SBOM once, that SBOM is scanned with Grype, signed with cosign, stored as an attestation and rescanned later without pulling the image again. It’s a separation of concerns that fits nicely in formal supply-chain security flows, SLSA-style.

In a pipeline that already produces SBOMs as an independent deliverable —increasingly common because it’s being required at regulatory level—, Grype becomes “the SBOM verifier,” which means generation and scanning can live in different pipeline phases, even on different machines. Trivy can also scan SBOMs, but the flow isn’t as polished.

SBOM-based vs File-based in Practice

The underlying technical difference is how packages are discovered. Grype, backed by Syft, first builds a detailed SBOM and then cross-references it against the vulnerability database. Trivy does both internally but is more optimised for direct image scanning, parsing package-manager metadata (dpkg, apk, rpm, pip, npm, go.mod, Cargo.lock) on the fly. In terms of results, for images with well-labelled system packages they’re practically equivalent. The difference shows up in interpreted languages with vendored dependencies or static Go binaries: Syft tends to recognise more packages because its discovery logic is more aggressive, which translates to more vulnerabilities found —not always real, but more.

False Positives in Production

This is where you have to be careful. Both tools report CVEs that technically exist in the package but aren’t exploitable in the actual context: the vulnerable function isn’t called, the OS version already patched it via backport (the typical Debian and Ubuntu case), or the CVE requires a network vector that doesn’t apply. After a year of measuring, Trivy tends to benefit slightly more from distro-specific patches because its database (Aqua + NVD + distro feeds) cross-references distro metadata, while Grype leans more on NVD directly. The net result is that on Debian and Alpine images, Trivy usually produces less noise; on distroless or static-binary images, the difference evens out.

The strategy that has worked is filtering HIGH and CRITICAL in CI as break-build policy, and leaving MEDIUM and below for weekly human review. Breaking the build every time a LOW CVE pops up in a transitive library just teaches the team to ignore the scanner.

Where Trivy Clearly Wins

The one terrain where Trivy wins without discussion is misconfiguration scanning. It checks Dockerfiles against best practices, runs Terraform modules against more than fifty rules, validates Kubernetes manifests against CIS Benchmark and renders Helm charts before analysing them. Grype, plainly, does none of this —its scope is vulnerabilities, not configuration—. If the team wants a single tool that answers “is this container secure?” including the container definition and not just its contents, Trivy is the answer.

CI Integration and K8s Admission

On GitHub Actions, both have vendor-maintained actions. Aqua’s Trivy action accepts image references, SARIF output format (which GitHub renders natively in the Security tab), severity threshold and configurable exit code. Anchore’s Grype action is more terse but equally functional. Integration friction is the same.

For Kubernetes admission, Trivy pairs well with Kyverno via policies that verify signed images and the absence of critical CVEs before allowing deployment:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-no-critical-cves
spec:
  rules:
    - name: check-critical-cves
      verifyImages:
        - imageReferences:
            - "*"
          required: true

The Trivy operator can feed this policy with its VulnerabilityReports, closing the loop between scanning and admission control.

Verdict

If I could only have one, Trivy. It covers more surface, has a better false-positive track record on mainstream distros, and the Kubernetes operator is a piece with no equivalent on the Anchore side. If the pipeline revolves around SBOMs as an independent deliverable, signed and verified separately, Grype with Syft fits that architecture better. And many teams end up running both as defense-in-depth: the cost of running both in CI is trivial compared to catching a CVE that one of them missed. After a year, that’s the honest conclusion —there’s no absolute winner, there are good fits and lukewarm fits.

Entradas relacionadas