What is Trivy?
Trivy is an open-source, all-in-one security scanner by Aqua Security. It scans for:
| Target | What it finds |
|---|
| Container images | OS package CVEs, language library CVEs |
| Filesystems | Same as above, on local directories |
| Git repositories | Secrets, CVEs in dependency files |
| IaC files | Misconfigurations in Terraform, Dockerfile, K8s manifests |
| SBOM | Vulnerabilities in a Software Bill of Materials |
Trivy is fast, has no server component, and is the most widely used container scanner in CI/CD pipelines.
Installation
1
2
3
4
5
6
7
8
| # Windows (via Scoop)
scoop install trivy
# Or download the binary from GitHub releases
# https://github.com/aquasecurity/trivy/releases
# Verify
trivy --version
|
Scanning Container Images
Basic Scan
1
| trivy image nginx:latest
|
Trivy scans:
- The OS packages (apt/apk/yum)
- Application libraries (pip, npm, gem, cargo, etc.)
- For each: checks its vulnerability database (NVD, GitHub Advisory, OS vendor advisories)
Filtering by Severity
1
2
3
4
5
| # Only show Critical and High
trivy image --severity CRITICAL,HIGH nginx:latest
# Only Critical
trivy image --severity CRITICAL nginx:latest
|
Failing CI on Critical Findings
1
2
| # Exit code 1 if any CRITICAL CVE is found: use this in CI to block the pipeline
trivy image --severity CRITICAL --exit-code 1 myapp:latest
|
If the scan finds a Critical CVE, the command exits with code 1, failing the pipeline step.
Scanning a Specific Architecture
1
| trivy image --platform linux/amd64 myapp:latest
|
Important when building multi-arch images on an ARM Mac - scan the architecture that will actually run in production.
1
2
3
4
5
6
7
8
| # JSON output (for parsing or feeding into other tools)
trivy image --format json --output results.json nginx:latest
# SARIF output (for GitHub Code Scanning)
trivy image --format sarif --output results.sarif nginx:latest
# Table (default)
trivy image --format table nginx:latest
|
Scanning Filesystems and Repos
Scan a Local Directory
1
2
3
4
| # Scan your project directory for vulnerabilities in dependency files
trivy fs .
# This picks up: package-lock.json, requirements.txt, Gemfile.lock, go.sum, etc.
|
Scan a Git Repository
1
2
3
4
5
| # Scan a remote repo without cloning
trivy repo https://github.com/yourusername/yourrepo
# Scan and also check for secrets
trivy repo --scanners vuln,secret https://github.com/yourusername/yourrepo
|
Scanning IaC Files
Trivy checks Dockerfiles, Terraform, Kubernetes manifests, and Helm charts for misconfigurations.
1
2
3
4
5
6
7
8
| # Scan a Dockerfile
trivy config Dockerfile
# Scan a Terraform directory
trivy config ./terraform/
# Scan a Kubernetes manifest
trivy config k8s-deployment.yaml
|
1
2
| # Scan your MindCraft Terraform code
trivy config ./terraform/ --severity MEDIUM,HIGH,CRITICAL
|
Secret Scanning
Trivy can scan for hardcoded secrets (API keys, passwords, tokens) in your codebase:
1
| trivy fs --scanners secret .
|
Trivy detects secrets like:
- AWS access keys
- GitHub tokens
- Private keys (RSA, EC)
- Generic API key patterns
Understanding CVE Output
Each finding shows:
| Field | Meaning |
|---|
| Library | The package with the vulnerability |
| Vulnerability ID | CVE identifier |
| Severity | CRITICAL / HIGH / MEDIUM / LOW |
| Installed Version | What you have |
| Fixed Version | What you need to upgrade to |
| Title | Short description of the vulnerability |
When “Fixed Version” is empty: No fix is available yet. Your options are:
- Accept the risk (document it)
- Switch to a different package
- Use a different base image that doesn’t include this package
Ignoring False Positives
Create a .trivyignore file in your project to suppress known false positives or accepted risks:
1
2
3
4
5
6
7
| # .trivyignore
# Accepted risk: no fix available, low exploitability in our context
CVE-2023-12345
# This CVE is in a test-only dependency, not in production
CVE-2023-67890
|
1
| trivy image --ignorefile .trivyignore myapp:latest
|
Integrating Trivy into GitHub Actions
Basic Image Scan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| # .github/workflows/trivy.yml
name: Trivy Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
trivy-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy image scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH
exit-code: 1
- name: Upload results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
|
The SARIF upload makes findings appear in the GitHub Security tab → Code scanning alerts.
Full Pipeline with IaC + Image Scan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| name: Full Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Trivy IaC scan
uses: aquasecurity/trivy-action@master
with:
scan-type: config
scan-ref: .
severity: HIGH,CRITICAL
exit-code: 0 # don't fail on IaC findings (informational for now)
- name: Build image
run: docker build -t myapp:test .
- name: Trivy image scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:test
severity: CRITICAL
exit-code: 1 # fail on Critical image CVEs
|
Lab: Scan a Public Image and Fix It
Objective: Scan an old image, understand the findings, update the base image, re-scan.
- Scan an old Python image:
1
| trivy image --severity CRITICAL,HIGH python:3.9
|
- Count the Critical findings:
1
| trivy image --severity CRITICAL --format json python:3.9 | jq '.Results[].Vulnerabilities | length'
|
- Scan the latest slim version:
1
| trivy image --severity CRITICAL,HIGH python:3.12-slim
|
- Update your Dockerfile
FROM line and rebuild - Re-scan your built image - verify CVE count dropped
Key Takeaways
- Trivy is a single binary that scans images, filesystems, repos, IaC, and secrets - use it everywhere
- Add
--exit-code 1 --severity CRITICAL to your CI pipeline to block on critical CVEs - Upload SARIF results to GitHub Security tab for persistent tracking
- Keep base images updated - most CVEs are in outdated OS packages
- Use
.trivyignore for accepted risks, not as a way to silence everything - Scan both the image AND the IaC in the same pipeline
References
You can find me online at: