Grype
.mdVerified against Grype 0.99.1, flags verified via `grype --help` run locally, 2026-08-29 · official docs
What it is and where it fits 🎯#
Grype is Anchore's vulnerability scanner for container images, filesystems, and SBOMs — narrower in scope than Trivy (no built-in IaC scanning, no secrets detection), but that narrowness is the point: it does one job — match a package inventory against known vulnerabilities — and does it fast, with a design that pairs naturally with its sibling tool Syft. The idiomatic Anchore workflow is "generate once, scan many times": Syft builds the SBOM, Grype (or Trivy, or a platform like Dependency-Track) consumes it. If a team already runs Trivy for everything, adding Grype purely for image scanning is redundant; Grype earns its place when a team wants Syft's SBOM generation and prefers Anchore's own matching engine over Trivy's for that half of the job.
How Grype resolves a scan target ⚙️#
The sbom: path is the fast one — Grype embeds the same cataloging library Syft uses, so scanning an image
directly re-does that cataloging work internally; feeding it an already-generated Syft SBOM skips straight to
vulnerability matching.
Installation#
curl -sSfL https://get.anchore.io/grype | sh -s -- -b /usr/local/bin
# add -v to also verify the downloaded binary's signature with cosign
brew install grype
grype versionScanning an image#
grype yourrepo/yourimage:tag # defaults to pulling from the local Docker daemon
grype docker:yourrepo/yourimage:tag # explicit Docker daemon source
grype registry:yourrepo/yourimage:tag # pull directly from a registry — no container runtime required
grype podman:yourrepo/yourimage:tag
grype docker-archive:path/to/image.tar # a `docker save` tarballScanning a filesystem or a purl/CPE directly#
grype dir:path/to/yourproject
grype file:path/to/yourfile
grype pkg:npm/lodash@4.17.15 # a single package URL, no source to scan
grype cpe:2.3:a:openssl:openssl:3.0.14:*:*:*:*:*:*:*Piping Syft SBOMs straight in#
syft yourimage:tag -o json | grype
grype sbom:path/to/syft.json # from a saved Syft SBOMTip
Generate the SBOM once at build time, store it as a build artifact, and scan it repeatedly afterward rather than re-pulling and re-scanning the image every time a new CVE feed lands. This is the same "instant search across everything we've ever built" pattern documented on the Syft and Trivy SBOM pages — a stored SBOM never goes stale about what's in the artifact, only the vulnerability data matched against it does, and that's a cheap re-match, not a re-scan.
Gating CI on severity#
grype myapp:latest --fail-on high # exit 1 if any HIGH-or-above vuln is found (0 by default!)Warning
Like Trivy, Grype's default exit code is 0 regardless of findings — --fail-on is what turns it into a
real CI gate. Confirmed the single most common cause of "the scanner ran but never blocked anything" reports
across every vulnerability scanner in this series (Trivy, Grype both share this default).
Filtering and output#
grype myapp:latest --only-fixed # hide vulns with no available fix
grype myapp:latest -o json > results.json
grype myapp:latest -o table # default, human-readable
grype myapp:latest -o cyclonedx-json > results.cdx.json
grype myapp:latest --scope all-layers # inspect every image layer, not just the squashed result
grype myapp:latest -s low --exclude '**/test/**'
grype myapp:latest --by-cve # orient results by CVE id instead of the internal vuln id — easier to cross-reference against an advisory feedSample table output (illustrative shape — actual CVEs, counts, and column widths depend entirely on the image scanned and the vuln DB's state that day):
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
openssl 1.1.1b-r1 1.1.1k-r0 apk CVE-2021-3711 Critical
libcurl 7.64.0-r2 7.64.0-r3 apk CVE-2020-8231 High
Explaining a finding 🔍#
grype myapp:latest -o json > results.json
grype explain --id CVE-2024-12345 -f results.json # why did this CVE match, what's the path to the vulnerable packageThis answers the question a raw finding list never does on its own: "my base image is alpine:3.18 — why is
Grype reporting a CVE against a package I never installed?" explain walks the match back to the specific
layer/package/version that triggered it.
Real-world scenario: comparing Syft+Grype against Trivy on the same image#
A team migrating from Trivy to the Syft/Grype pairing (or vice versa) should expect some non-overlap — the two use different vulnerability data sources and matching logic, so a side-by-side run on the same image is worth doing before fully committing:
trivy image --format json --output trivy-results.json myapp:latest
syft myapp:latest -o json | grype -o json > grype-results.json
# diff the CVE ID lists from each report — expect partial, not total, overlapNote
Neither tool is strictly a superset of the other. A production security pipeline that genuinely can't tolerate a missed finding sometimes runs both and unions the results, accepting the operational cost of maintaining two scanners for the coverage gain.
Real-world scenario: GitHub Actions CI recipe#
# .github/workflows/grype.yml
name: Grype Image Scan
on: [pull_request]
jobs:
grype:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- uses: anchore/scan-action@v4
id: scan
with:
image: myapp:${{ github.sha }}
fail-build: true
severity-cutoff: high
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: ${{ steps.scan.outputs.sarif }}Shell completion#
grype completion bash | sudo tee /etc/bash_completion.d/grypeCommon pitfalls#
- Assuming
--fail-onis the default behavior — it isn't; a baregrype myapp:latestin CI with no exit gating never fails a build regardless of what it finds. - Scanning
latestand comparing results day-to-day — a mutable tag drifts; pin to a digest for anything you intend to track as a trend. - Expecting identical results to Trivy — different data sources produce different (overlapping, not identical) findings; don't treat either tool's output as the sole ground truth.
Exit codes#
0 clean (or findings exist but --fail-on not set) · 1 findings at/above the --fail-on severity
threshold.
When to reach for something else#
For IaC misconfigurations, secrets, or a single tool covering everything, Trivy is the broader option — see its two cheat-sheet pages in this section. For SBOM generation specifically, pair Grype with Syft rather than reaching for Trivy's built-in SBOM support, if Anchore's matching engine is the one the team has standardized on.