Container images are your application’s most deployable artifact — and potentially its biggest attack surface. Every base image you inherit, every dependency you install, every layer you cache carries potential vulnerabilities. Trivy is a fast, comprehensive scanner that catches these issues before they reach production. Let’s set it up properly.
Why Trivy Over Alternatives
Several container scanners exist — Clair, Grype, Snyk — but Trivy stands out for three reasons: it’s a single binary with zero dependencies, it scans both OS packages and language-specific dependencies (Go, Node.js, Python, etc.), and it’s fast enough to run on every build. The Aqua Security team maintains it with regular vulnerability database updates.
Installing Trivy
# macOS
brew install trivy
# Linux (Debian/Ubuntu)
sudo apt-get install trivy
# Or grab the binary directly
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
# Verify
trivy --version
Scanning Your First Image
# Basic scan — finds known CVEs
trivy image my-app:latest
# Filter to only HIGH and CRITICAL
trivy image --severity HIGH,CRITICAL my-app:latest
# Output as JSON for CI integration
trivy image --format json --output scan-results.json my-app:latest
The output shows each vulnerability with its CVE ID, affected package, installed version, and the version that fixes it. Trivy draws from multiple databases: NVD, GHSA, and distro-specific advisories like Debian’s DSA.
Integrating Into CI/CD
The real value comes from running Trivy automatically on every push. Here’s a GitHub Actions setup that fails builds on critical vulnerabilities:
# .github/workflows/security-scan.yml
name: Container Security Scan
on:
push:
branches: [main]
pull_request:
jobs:
trivy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t app:${{ github.sha }} .
- name: Run Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: app:${{ github.sha }}
format: table
exit-code: 1
ignore-unfixed: true
severity: CRITICAL,HIGH
vuln-type: os,library
The exit-code: 1 flag makes the step fail when vulnerabilities are found, blocking the PR merge. The ignore-unfixed: true flag filters out vulnerabilities that don’t have a known fix — actionable findings only.
Scanning Infrastructure as Code
Trivy also scans Dockerfiles, Kubernetes manifests, and Terraform configurations for misconfigurations — not just vulnerabilities:
# Scan a Dockerfile for best practices
trivy config Dockerfile
# Scan Kubernetes manifests
trivy config ./k8s/
# Scan Terraform
trivy config ./terraform/
This catches issues like running as root, not setting resource limits, exposing sensitive ports, or using deprecated Kubernetes APIs. It’s like having a security-focused linter for your infrastructure.
Building a .trivyignore Responsibly
Some vulnerabilities can’t be fixed immediately — maybe the patched version breaks a dependency, or the vulnerable code path isn’t reachable. Trivy supports an ignore file:
# .trivyignore
CVE-2024-12345 # Pending upstream fix, expected in v2.3
CVE-2024-67890 # False positive — vulnerable code not linked
Every entry should have a comment explaining why it’s ignored and when it can be removed. Review this file monthly — stale ignores accumulate technical debt silently.
SBOM Generation
Software Bills of Materials are becoming mandatory for supply chain compliance. Trivy generates SBOMs in standard formats:
# Generate CycloneDX SBOM
trivy image --format cyclonedx --output sbom.json my-app:latest
# Generate SPDX SBOM
trivy image --format spdx-json --output sbom.spdx.json my-app:latest
Store these artifacts alongside your releases. If a new CVE is disclosed, you can immediately check whether your deployed images contain the affected package without re-scanning.
Putting It All Together
A robust container scanning pipeline combines image scans, config scans, and SBOM generation into your build process. The setup cost is minimal — Trivy is free, fast, and integrates with existing CI platforms. The payoff is catching vulnerabilities before they become incidents, and having the documentation ready when auditors ask.
Start with a simple trivy image scan on your most-deployed image. You might be surprised by what’s hiding in those base layers.