Ir al contenido

Grype

Overview

Grype is an open-source vulnerability scanner from Anchore. It finds known CVEs in container images, filesystems, and SBOMs (Software Bill of Materials) by matching packages against databases including NVD, GitHub Security Advisories, OS vendor feeds (Alpine, Debian, Ubuntu, RHEL, etc.), and language ecosystem advisories (PyPI, npm, Maven, Go, Rust). Grype pairs naturally with Syft (SBOM generation) and integrates into CI/CD pipelines, Kubernetes admission controllers, and Anchore Enterprise.

Installation

Linux (curl installer)

curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
grype version

Homebrew (macOS / Linux)

brew install grype

Docker (no install required)

docker run --rm anchore/grype:latest alpine:3.19

Go install

go install github.com/anchore/grype/cmd/grype@latest

Verify and update DB

grype version
grype db update       # Pull latest vulnerability database
grype db status       # Show current DB version and age

Configuration

Config file locations

Grype checks these paths in order:

  • .grype.yaml (project root)
  • ~/.grype.yaml
  • ~/.config/grype/config.yaml

.grype.yaml reference

# Output format: table | json | cyclonedx | sarif | template
output: table

# Fail on severity: negligible | low | medium | high | critical
fail-on-severity: high

# Severity filter (only report these and above)
severity: medium

# Ignore specific vulnerabilities
ignore:
  - vulnerability: CVE-2023-12345
    reason: "Not exploitable in our configuration"
  - vulnerability: CVE-2022-99999
    package:
      name: openssl
      version: 1.1.1k
      type: rpm
  - fix-state: not-fixed     # Ignore all unfixed vulns (risky)
  - package:
      language: python
      name: requests

# Database configuration
db:
  cache-dir: ~/.cache/grype
  update-url: https://toolbox-data.anchore.io/grype/databases/listing.json
  auto-update: true
  validate-age: true
  max-allowed-built-age-hours: 120

# Scope for directory scans: squashed | all-layers
scope: squashed

# Add CPE matching
add-cpes-if-none: true

# External sources (GitHub token for GHSA)
external-sources:
  enable: true
  maven:
    search-upstream-by-sha1: true
    base-url: https://search.maven.org/solrsearch/select

Core Commands

CommandDescription
grype alpine:3.19Scan a Docker Hub image
grype nginx:latestScan nginx image from registry
grype dir:.Scan current filesystem directory
grype dir:/appScan specific directory
grype sbom:./bom.jsonScan a CycloneDX or SPDX SBOM
grype file:./binaryScan a single binary file
grype registry:myregistry/image:tagScan from private registry
grype oci-dir:./extracted-image/Scan an OCI layout directory
grype docker:./image.tarScan a saved Docker image tar
grype . --fail-on highExit non-zero if high+ CVEs found
grype . -o jsonOutput as JSON
grype . -o sarifOutput SARIF for GitHub Advanced Security
grype . -o cyclonedxOutput CycloneDX VEX
grype . --severity highOnly show high and critical
grype . --add-cpes-if-noneEnhance matching with CPE generation
grype . --scope all-layersScan all image layers, not just squashed
grype db updateUpdate vulnerability database
grype db listList available database versions
grype db checkCheck if DB update is available
grype configShow current effective configuration
grype versionShow version and DB info

Advanced Usage

Severity filtering and CI gating

# Fail the pipeline on critical vulnerabilities
grype myapp:latest --fail-on critical
echo "Exit code: $?"   # 0 = pass, 1 = vulnerabilities found

# Fail on high and above
grype myapp:latest --fail-on high

# Only report medium and above (suppress noise)
grype myapp:latest --severity medium

# Combine: report medium+, fail on critical
grype myapp:latest --severity medium --fail-on critical

Working with SBOMs (Syft integration)

# Generate SBOM with Syft, then scan with Grype
syft alpine:3.19 -o json > sbom.json
grype sbom:sbom.json

# Generate and pipe directly
syft alpine:3.19 -o json | grype

# Use CycloneDX format
syft myapp:latest -o cyclonedx-json > sbom-cyclonedx.json
grype sbom:sbom-cyclonedx.json -o sarif > results.sarif

Ignore rules in config

# .grype.yaml
ignore:
  # Ignore specific CVE everywhere
  - vulnerability: CVE-2023-44487

  # Ignore CVE only for specific package
  - vulnerability: CVE-2021-44228
    package:
      name: log4j-core
      version: 2.14.1

  # Ignore all unfixed vulnerabilities
  - fix-state: not-fixed

  # Ignore by namespace
  - namespace: github:language:python

  # Ignore by package type
  - package:
      type: java

  # Ignore with expiry (manual enforcement needed)
  - vulnerability: CVE-2022-1234
    reason: "Tracked in JIRA-567, expires 2024-01-01"

Output formats

# Table (default, human-readable)
grype myapp:latest

# JSON (machine-readable, full detail)
grype myapp:latest -o json | jq '.matches[] | {name:.artifact.name, cve:.vulnerability.id, severity:.vulnerability.severity}'

# SARIF (GitHub Code Scanning)
grype myapp:latest -o sarif > grype-results.sarif

# CycloneDX (VEX, vulnerability exchange)
grype myapp:latest -o cyclonedx

# Template (custom output)
grype myapp:latest -o template -t my-template.tmpl

Private registry scanning

# Docker credential helpers are used automatically
# Or set explicitly:
export GRYPE_REGISTRY_AUTH_USERNAME=myuser
export GRYPE_REGISTRY_AUTH_PASSWORD=mytoken

grype registry:my-registry.example.com/myapp:1.0.0

# With TLS verification disabled (use carefully)
grype --insecure-skip-tls-verify registry:my.internal-registry.com/app:v1

Comparison: Grype vs Trivy

FeatureGrypeTrivy
LanguageGoGo
Primary focusContainer + SBOM scanningMulti-target scanning
SBOM inputCycloneDX, SPDXCycloneDX, SPDX
SBOM outputVia SyftBuilt-in
Misconfig scanningNoYes
Secret scanningNoYes
Kubernetes scanningVia Anchore EnterpriseBuilt-in
DB update frequencyDailyDaily
Anchore integrationNativeThird-party
GitHub Actionsanchore/scan-actionaquasecurity/trivy-action

Common Workflows

GitHub Actions integration

name: Container Security Scan
on: [push, pull_request]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build image
        run: docker build -t myapp:${{ github.sha }} .

      - name: Scan with Grype
        uses: anchore/scan-action@v4
        id: scan
        with:
          image: myapp:${{ github.sha }}
          fail-build: true
          severity-cutoff: high
          output-format: sarif

      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: ${{ steps.scan.outputs.sarif }}

Dockerfile scanning in CI

# Build and immediately scan
docker build -t myapp:latest .
grype myapp:latest --fail-on high -o json | tee grype-output.json

# Parse results
CRITICAL=$(jq '[.matches[] | select(.vulnerability.severity=="Critical")] | length' grype-output.json)
echo "Critical vulnerabilities: $CRITICAL"
[ "$CRITICAL" -eq 0 ] || exit 1

Offline / air-gapped environments

# On internet-connected machine: download DB archive
grype db list                          # Find latest listing URL
# Download the DB tarball manually from listing.json URL
# Transfer to air-gapped machine

# On air-gapped machine:
grype db import grype-db-5.tar.gz
grype --offline myapp:latest           # Skip DB update check

Scheduled vulnerability monitoring

#!/bin/bash
# scan-images.sh — run nightly in cron
IMAGES=("myapp:production" "myapp:staging")
for img in "${IMAGES[@]}"; do
    echo "Scanning $img"
    grype "$img" --fail-on critical -o json \
        > "grype-$(echo $img | tr '/:' '-').json"
done
# Send report via email or Slack webhook

Tips and Best Practices

Update the database before every scan. The vulnerability database is updated daily. Run grype db update at the start of your CI job or before local scans to avoid missing recent CVEs.

Use --fail-on critical in CI gates. Block deployments on critical vulnerabilities but use --severity medium for reporting so you see the full picture without failing on every medium-severity issue.

Combine with Syft for SBOM-first workflows. Generate a SBOM with Syft once, store it as a build artifact, then scan the SBOM with Grype in separate jobs. This decouples image building from scanning and enables re-scanning stored SBOMs later.

Do not use fix-state: not-fixed ignores in production gates. Ignoring unfixed vulnerabilities entirely defeats the purpose of scanning. Instead, track them in your issue tracker and set reminder dates.

Scope to all-layers for thorough audits. The default squashed scope is faster but can miss packages installed and then deleted in intermediate layers. Use --scope all-layers for security audits.

Pin the Grype version in CI. Use anchore/scan-action@v4 with a specific version tag to avoid behavior changes from automatic updates breaking your pipeline.

Use SARIF output for GitHub Advanced Security. Uploading SARIF results surfaces vulnerabilities directly in pull requests and the repository Security tab, making review much easier.

Separate ignore files per environment. Maintain different .grype.yaml files for development (lenient) and production (strict) scanning, committed alongside Dockerfiles for each deployment target.