What is Grype?
Grype is an open-source vulnerability scanner developed by Anchore that specializes in identifying known security vulnerabilities in container images, filesystems, and software packages. It works by analyzing the software components present in your artifacts and cross-referencing them against multiple curated vulnerability databases to surface actionable findings.
Unlike traditional scanners that rely solely on Common Vulnerabilities and Exposures (CVE) databases, Grype integrates data from numerous sources including NIST's National Vulnerability Database (NVD), GitHub Security Advisories, Red Hat's security data, Alpine SecDB, and more. This multi-source approach significantly improves coverage and reduces false negatives.
Grype is designed to be fast, easy to integrate, and works seamlessly with Syft — Anchore's Software Bill of Materials (SBOM) generator. Together, they form a powerful toolkit for generating and analyzing SBOMs in modern software supply chain security workflows.
Key Features at a Glance
- Multi-source vulnerability matching — Combines data from NVD, GitHub, Red Hat, Alpine, Debian, and more
- Container image scanning — Works directly with Docker, OCI, and Singularity images
- Filesystem and directory scanning — Scan local paths, not just container images
- SBOM ingestion — Consume existing SBOM documents in SPDX or CycloneDX format
- Multiple output formats — Table, JSON, CycloneDX, and SARIF for integration flexibility
- Severity filtering — Filter results by critical, high, medium, low, or negligible severity
- Vulnerability allowlists — Suppress findings based on CVE ID, package name, or path
- CI/CD native — Exit codes and structured output for pipeline integration
Why Grype Matters for Modern Development
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →Software supply chain attacks have increased dramatically. In recent years, high-profile incidents involving compromised dependencies, malicious container images, and zero-day exploits have underscored the critical need for continuous vulnerability scanning throughout the development lifecycle. Grype addresses this need by providing:
Shift-Left Security Validation
By integrating Grype early in development, teams can identify vulnerabilities before code reaches production. Scanning container images during CI builds, for instance, allows developers to catch and remediate issues at the pull request stage rather than discovering them post-deployment when remediation costs are highest.
SBOM-Driven Transparency
Grype works hand-in-hand with SBOM generation tools like Syft. An SBOM is a formal, machine-readable inventory of all components in a software artifact. Grype consumes these SBOMs to produce precise vulnerability reports, enabling organizations to comply with emerging regulatory requirements such as Executive Order 14028 in the United States, which mandates SBOM usage for government software suppliers.
Continuous Compliance
For teams operating in regulated industries, Grype's structured output formats (JSON, SARIF) make it straightforward to integrate findings into compliance dashboards, ticketing systems, and automated enforcement pipelines. You can fail builds based on vulnerability severity thresholds, ensuring only compliant artifacts reach production.
Installation Guide
Grype is distributed as a single static binary with no runtime dependencies, making installation trivial across platforms. Here are the recommended installation methods:
macOS / Linux via curl
# Download and install the latest version
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
# Verify the installation
grype version
Using Homebrew (macOS / Linux)
brew tap anchore/grype
brew install grype
# Verify
grype version
Docker Image (No Local Installation Required)
# Run Grype directly via Docker
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
anchore/grype:latest docker-image alpine:latest
Windows via Chocolatey
choco install grype
# Verify
grype version
Manual Download
Pre-built binaries for all platforms are available on the GitHub releases page. Download the appropriate archive, extract it, and place the binary in your PATH.
Core Usage Patterns
Scanning a Container Image
The most common use case is scanning a container image directly from a registry or your local Docker daemon:
# Scan a remote image from Docker Hub
grype docker-image alpine:latest
# Scan an image from a private registry
grype docker-image myregistry.example.com/app:v1.2.3
# Scan a locally tagged image
grype docker-image my-local-image:dev
Grype will pull the image, catalog its software packages, and match them against vulnerability databases. Results are displayed as a formatted table by default, showing the vulnerability ID, severity, affected package, installed version, and fix version where available.
Scanning a Local Directory or Filesystem
You can scan any directory containing software artifacts — this is particularly useful for scanning application dependencies, virtual machine images, or source repositories with vendored libraries:
# Scan the current directory
grype dir .
# Scan a specific directory
grype dir /path/to/your/project
# Scan an unpacked container image filesystem
grype dir ./extracted-rootfs
Scanning from an SBOM File
If you have already generated an SBOM with Syft or another tool, you can feed it directly to Grype for vulnerability analysis:
# Generate an SBOM with Syft and pipe to Grype
syft alpine:latest -o json | grype
# Or scan a saved SBOM file
grype sbom:./my-sbom.spdx.json
# CycloneDX format is also supported
grype sbom:./my-sbom.cyclonedx.xml
This decoupled workflow is powerful: you can generate SBOMs once and scan them repeatedly as vulnerability databases are updated, without re-accessing the original artifact.
Output Formats and Reporting
Grype supports several output formats to suit different integration needs. The default is a human-readable table, but structured formats are essential for automation.
JSON Output
# Produce detailed JSON output
grype docker-image alpine:latest -o json
# Save to a file
grype docker-image alpine:latest -o json > grype-results.json
The JSON output includes the full vulnerability data including descriptions, URLs, affected package details, and CVSS scores. This is the preferred format for programmatic processing and integration with dashboards.
SARIF Output
SARIF (Static Analysis Results Interchange Format) is a standardized format supported by GitHub, GitLab, Azure DevOps, and many other platforms:
grype docker-image alpine:latest -o sarif > results.sarif
# Upload to GitHub Code Scanning
# results.sarif can be uploaded via the GitHub API or actions
CycloneDX Output
Grype can output vulnerability-enriched CycloneDX documents, embedding vulnerability findings directly into the SBOM format:
grype docker-image alpine:latest -o cyclonedx-json > vuln-sbom.json
Customizing Table Output
# Add CVE descriptions to the table view
grype docker-image alpine:latest -o table --add-cpes
# Show only critical and high vulnerabilities
grype docker-image alpine:latest --severity critical,high
# Exclude negligible findings
grype docker-image alpine:latest --exclude-severity negligible
Filtering and Suppressing Results
Severity-Based Filtering
Use the --severity flag to limit results to specific severity levels. This is particularly useful in CI pipelines where you may want to fail only on critical findings:
# Only show critical and high vulnerabilities
grype docker-image app:latest --severity critical,high
# Exclude negligible and unknown severity
grype docker-image app:latest --exclude-severity negligible,unknown
# Fail build only on critical vulnerabilities
grype docker-image app:latest --fail-on critical
Vulnerability Allowlists (Suppression)
Not all vulnerabilities are immediately exploitable in your specific context. Grype supports allowlist configurations to suppress findings that have been reviewed and accepted:
# Using a YAML configuration file
grype docker-image app:latest -c grype-allowlist.yaml
Example grype-allowlist.yaml:
# grype-allowlist.yaml
ignore:
# Suppress a specific CVE across all packages
- vulnerability: CVE-2023-12345
type: cve
reason: "Reviewed: This CVE requires local access which is not available"
# Suppress based on package name and version
- package:
name: libssl
version: 1.1.1k
type: package
reason: "Vendor-confirmed patch backported, version string not updated"
# Suppress based on path within the image
- path: /usr/local/lib/debug/*
type: path
reason: "Debug symbols only, not deployed in production"
# Suppress an entire namespace of vulnerabilities
- namespace: debian:unstable
type: namespace
reason: "Testing-only packages, not used at runtime"
The allowlist mechanism is essential for keeping scan results actionable — without it, teams often suffer from alert fatigue as the same accepted risks appear repeatedly.
Database Management
Grype maintains a local vulnerability database that is automatically downloaded on first use and periodically updated. Understanding database management helps ensure accurate results.
Checking Database Status
# View current database information
grype db status
# Sample output:
# Location: /home/user/.cache/grype/db/5
# Built: 2024-01-15 08:30:00 UTC
# Schema version: 5
# Update available: No
Updating the Database
# Force update the vulnerability database
grype db update
# Check for updates without downloading
grype db check
Database Location
The database cache is stored at ~/.cache/grype/db/ on Linux/macOS. In CI environments, you may want to cache this directory between runs to avoid repeated downloads:
# Example GitHub Actions cache configuration
# Cache key: grype-db-{runner.os}
# Path: ~/.cache/grype/db/
CI/CD Pipeline Integration
GitHub Actions Integration
Here's a complete GitHub Actions workflow that scans container images during CI:
name: Container Vulnerability Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
vulnerability-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Grype
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | \
sh -s -- -b ${{ github.workspace }}/bin
echo "${{ github.workspace }}/bin" >> $GITHUB_PATH
- name: Build container image
run: |
docker build -t my-app:${{ github.sha }} .
- name: Scan image with Grype
run: |
grype docker-image my-app:${{ github.sha }} \
--severity critical,high \
--fail-on critical \
-o sarif > grype-results.sarif
continue-on-error: true
- name: Upload SARIF results to GitHub
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: grype-results.sarif
- name: Check for critical vulnerabilities
run: |
grype docker-image my-app:${{ github.sha }} \
--severity critical \
--fail-on critical \
-o json > critical-check.json
echo "If we reach here, no critical vulnerabilities found"
GitLab CI Integration
# .gitlab-ci.yml
vulnerability-scan:
stage: security
image: docker:24
services:
- docker:24-dind
variables:
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_CERTDIR: "/certs"
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- apk add curl
- curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- grype docker-image $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --severity critical,high --fail-on critical -o json > scan-report.json
artifacts:
paths:
- scan-report.json
expire_in: 30 days
allow_failure: false
Jenkins Pipeline (Declarative)
// Jenkinsfile
pipeline {
agent any
environment {
GRYPE_VERSION = 'latest'
}
stages {
stage('Install Grype') {
steps {
sh '''
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | \
sh -s -- -b /usr/local/bin
'''
}
}
stage('Build Image') {
steps {
sh 'docker build -t my-app:${BUILD_TAG} .'
}
}
stage('Vulnerability Scan') {
steps {
sh '''#!/bin/bash
grype docker-image my-app:${BUILD_TAG} \
--severity critical,high \
--fail-on critical \
-o json > grype-scan-${BUILD_TAG}.json
'''
archiveArtifacts artifacts: "grype-scan-${BUILD_TAG}.json"
}
}
stage('Evaluate Results') {
steps {
sh '''#!/bin/bash
CRITICAL_COUNT=$(grype docker-image my-app:${BUILD_TAG} \
--severity critical -o json | jq '.matches | length')
if [ "$CRITICAL_COUNT" -gt 0 ]; then
echo "Found $CRITICAL_COUNT critical vulnerabilities - failing build"
exit 1
fi
echo "No critical vulnerabilities found"
'''
}
}
}
}
Advanced Configuration
Configuration File Reference
Grype supports a YAML configuration file that can be placed at standard locations or specified explicitly:
# Default locations Grype checks (in order):
# 1. .grype.yaml (current directory)
# 2. .grype/config.yaml (current directory)
# 3. ~/.grype/config.yaml (user home)
# 4. XDG config path
# Or specify explicitly
grype docker-image app:latest -c /path/to/custom-config.yaml
Example comprehensive configuration:
# .grype.yaml
# Vulnerability database options
db:
# Auto-update check interval (default: true)
auto-update: true
# Maximum number of days between database updates
max-update-age-days: 5
# Custom database cache location
cache-dir: /shared/cache/grype-db
# Check for available updates on startup
check-for-app-update: false
# Default output settings
output: json
# Severity filter applied globally
severity:
- critical
- high
- medium
# Allowlist configuration
ignore:
- vulnerability: CVE-2022-0001
type: cve
reason: "Accepted risk - requires privileged access"
- package:
name: curl
version: 7.79.1
type: package
reason: "Patched internally, version not bumped"
# Registry authentication
registry:
auth:
- url: https://my-registry.example.com
username: ${REGISTRY_USER}
password: ${REGISTRY_PASSWORD}
# Or use token-based auth
# token: ${REGISTRY_TOKEN}
# Mirror configuration for air-gapped environments
mirror: https://internal-mirror.example.com/grype-db
Air-Gapped and Offline Environments
For environments without internet access, Grype supports offline database updates:
# Step 1: On an internet-connected machine, export the database
grype db export /tmp/grype-db-export.tar.gz
# Step 2: Transfer the archive to your air-gapped environment
# Step 3: Import the database on the offline machine
grype db import /path/to/grype-db-export.tar.gz
# Step 4: Verify import
grype db status
# Step 5: Scan with --offline flag to prevent any network calls
grype docker-image my-internal-image:latest --offline
Working with Syft for SBOM-Based Workflows
Grype and Syft are designed as complementary tools. Here's how to build a complete SBOM-driven vulnerability management pipeline:
Generate SBOM and Scan in One Step
# Pipe Syft output directly to Grype
syft packages docker-image my-app:latest -o json | grype
# Generate SBOM, save it, then scan it later
syft packages docker-image my-app:latest -o spdx-json > sbom.spdx.json
grype sbom:sbom.spdx.json -o json > vulnerability-report.json
Continuous SBOM Scanning Script
#!/bin/bash
# scan-artifact.sh - Generate SBOM and scan for vulnerabilities
set -e
ARTIFACT_IMAGE="${1:-alpine:latest}"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
SBOM_DIR="./sboms"
REPORT_DIR="./reports"
mkdir -p "$SBOM_DIR" "$REPORT_DIR"
echo "=== Generating SBOM for $ARTIFACT_IMAGE ==="
SBOM_FILE="$SBOM_DIR/sbom-${TIMESTAMP}.spdx.json"
syft packages "docker-image:$ARTIFACT_IMAGE" -o spdx-json > "$SBOM_FILE"
echo "SBOM saved to $SBOM_FILE"
echo "=== Scanning SBOM for vulnerabilities ==="
REPORT_FILE="$REPORT_DIR/vuln-report-${TIMESTAMP}.json"
grype "sbom:$SBOM_FILE" -o json > "$REPORT_FILE"
echo "Vulnerability report saved to $REPORT_FILE"
echo "=== Summary ==="
CRITICAL=$(jq '[.matches[] | select(.vulnerability.severity == "Critical")] | length' "$REPORT_FILE")
HIGH=$(jq '[.matches[] | select(.vulnerability.severity == "High")] | length' "$REPORT_FILE")
TOTAL=$(jq '.matches | length' "$REPORT_FILE")
echo "Total vulnerabilities: $TOTAL"
echo "Critical: $CRITICAL | High: $HIGH"
Programmatic Usage via the Go Library
For teams building custom security tooling in Go, Grype can be used as an embedded library. This allows you to integrate vulnerability scanning directly into your applications:
package main
import (
"context"
"fmt"
"os"
"github.com/anchore/grype/grype"
"github.com/anchore/grype/grype/db"
"github.com/anchore/grype/grype/match"
"github.com/anchore/grype/grype/vulnerability"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/source"
)
func main() {
ctx := context.Background()
// Step 1: Generate a software catalog using Syft's library
src, err := source.NewFromDockerImage("alpine:latest", "")
if err != nil {
fmt.Fprintf(os.Stderr, "failed to create source: %v\n", err)
os.Exit(1)
}
catalog, _, _, err := syft.CatalogPackages(src, syft.DefaultConfig())
if err != nil {
fmt.Fprintf(os.Stderr, "failed to catalog: %v\n", err)
os.Exit(1)
}
// Step 2: Load vulnerability database
dbConfig := db.Config{
DBPath: "~/.cache/grype/db/5",
}
vulnStore, err := db.NewVulnerabilityProvider(dbConfig)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to load db: %v\n", err)
os.Exit(1)
}
// Step 3: Run vulnerability matching
matches, err := grype.FindVulnerabilities(
ctx,
vulnStore,
catalog,
grype.VulnerabilityMatcherConfig{
MatchByPackage: true,
MatchByCPE: true,
},
)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to find vulnerabilities: %v\n", err)
os.Exit(1)
}
// Step 4: Process results
for _, m := range matches {
fmt.Printf("Vulnerability: %s | Severity: %s | Package: %s\n",
m.Vulnerability.ID,
m.Vulnerability.Severity,
m.Package.Name,
)
}
fmt.Printf("Total matches found: %d\n", len(matches))
}
Best Practices for Production Deployments
1. Establish Severity Thresholds and SLAs
Define clear policies for vulnerability remediation based on severity. A common approach:
- Critical vulnerabilities: Must be fixed before deployment — block the CI pipeline
- High vulnerabilities: Fix within 30 days; create an automatic ticket if detected in production
- Medium vulnerabilities: Fix within 90 days; track in backlog
- Low/negligible: Document and review quarterly
2. Implement Layered Scanning
Don't rely on a single scan point. Implement multiple scanning gates:
# Pre-commit: Scan dependencies in the source tree
grype dir .
# CI build: Scan the built container image
grype docker-image built-image:${CI_COMMIT_SHA}
# Registry admission: Scan before promoting to production registry
grype docker-image registry.example.com/app:staging
# Continuous production monitoring: Periodic re-scanning
# Schedule a cron job to re-scan deployed images weekly
3. Maintain an Active Allowlist
Keep your allowlist configuration in version control alongside your application code. Require peer review for allowlist additions. Each entry should include a mandatory reason and an expiration date:
# .grype.yaml committed to repository
ignore:
- vulnerability: CVE-2023-XXXXX
type: cve
reason: "Reviewed by security team on 2024-01-15. Internal network isolation mitigates exposure."
expires: 2024-07-15 # Require re-review after 6 months
4. Cache the Vulnerability Database
In CI environments, cache the Grype database to reduce scan time and avoid rate limiting from upstream sources:
# GitHub Actions cache example
- name: Cache Grype DB
uses: actions/cache@v4
with:
path: ~/.cache/grype/db
key: grype-db-${{ runner.os }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
grype-db-${{ runner.os }}-
# Then run Grype - it will only update if cache is stale
- run: grype docker-image my-app:latest --fail-on critical
5. Combine Grype with Additional Scanners
Grype excels at vulnerability detection, but no single tool catches everything. Combine it with complementary tools:
- Trivy — For broader CVE coverage and misconfiguration scanning
- Docker Scout / Snyk — For additional advisory sources
- Cosign — For image signing and attestation verification
- Falco — For runtime threat detection complementing pre-deployment scanning
6. Automate SBOM Generation and Archiving
Generate and store SBOMs for every build. These serve as an audit trail and enable rapid impact analysis when new vulnerabilities are disclosed:
#!/bin/bash
# Generate and archive SBOM for every release
RELEASE_TAG="${1}"
syft packages docker-image:my-app:${RELEASE_TAG} \
-o cyclonedx-json > sbom-${RELEASE_TAG}.cdx.json
# Store in artifact repository with metadata
# Consider tools like OCI registries for SBOM storage
oras push my-registry.example.com/sboms/my-app:${RELEASE_TAG} \
sbom-${RELEASE_TAG}.cdx.json:application/vnd.cyclonedx+json
7. Integrate Findings into Developer Workflow
Don't let vulnerability reports sit in a silo. Surface findings where developers work:
- Upload SARIF results to GitHub Code Scanning for inline PR annotations
- Post scan summaries as PR comments via CI automation
- Create Jira/GitHub issues automatically for high-severity findings
- Include vulnerability counts in team dashboards and sprint retrospectives
Troubleshooting Common Issues
Database Update Failures
# If database update fails, check connectivity
grype db check --verbose
# Force a fresh database download
rm -rf ~/.cache/grype/db/
grype db update
# If behind a proxy, set environment variables
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
grype db update
Image Pull Failures
# For private registries, configure authentication
grype docker-image private.registry.example.com/app:latest \
-c registry-config.yaml
# registry-config.yaml
registry:
auth:
- url: https://private.registry.example.com
username: ${REGISTRY_USER}
password: ${REGISTRY_PASSWORD}
# Or use Docker credential helpers
# Grype respects ~/.docker/config.json by default
False Positives and Missing Matches
# Enable verbose output to see matching decisions
grype docker-image app:latest -vv
# Check which vulnerability sources are active
grype db status --verbose
# If a known vulnerability is not detected, verify:
# 1. The package is actually present (use syft to list packages)
# 2. The vulnerability exists in Grype's data sources
# 3. The version comparison is working correctly
Conclusion
Grype has established itself as a foundational tool in modern software supply chain security. Its combination of speed, multi-source vulnerability data, flexible output formats, and tight integration with SBOM workflows makes it an excellent choice for teams looking to implement continuous vulnerability scanning without adding significant friction to their development process.
The key to success with Grype is not just running scans, but embedding them thoughtfully into your development lifecycle. Start by establishing severity-based policies, implementing scanning at multiple stages (source, build, registry, and production), and maintaining a disciplined allowlist practice. Combine Grype with complementary tools like Syft for SBOM generation and Cosign for artifact signing to build a comprehensive supply chain security posture.
As regulatory requirements around SBOMs and vulnerability disclosure continue to evolve, tools like Grype will become increasingly essential. Investing in these practices today positions your team to meet tomorrow's compliance demands while meaningfully reducing your attack surface. The complete implementation patterns covered in this guide — from basic scanning through CI/CD integration, air-gapped deployment, and programmatic embedding — provide a solid foundation for building security into every stage of your software delivery pipeline.