devsecops
Trivy: Container Image Scanning Guide
Intermediate
12 minutes
October 2026
CloudOpsGuide Team
Trivy: Container Image Scanning Guide
Scan Docker images, Kubernetes clusters, filesystems, and IaC for vulnerabilities and misconfigurations with Trivy — the industry-standard open-source scanner.
Table of Contents
- What is Trivy
- Installation
- Scanning Container Images
- Scanning Kubernetes
- Filesystem and IaC Scanning
- CI/CD Integration
- Filtering and Reporting
What is Trivy
Trivy is an open-source vulnerability scanner by Aqua Security that detects:
- OS package vulnerabilities (Alpine, Debian, RHEL, etc.)
- Language dependency vulnerabilities (npm, pip, Go modules, Maven...)
- Misconfigurations in Kubernetes, Terraform, Dockerfiles
- Secrets accidentally committed (API keys, passwords)
- License compliance issues
Installation
# macOS
brew install trivy
# Linux
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin
# Docker (no install needed)
docker run --rm aquasec/trivy:latest image nginx:latest
# Verify
trivy version
Scanning Container Images
Basic Scan
# Scan an image
trivy image nginx:1.25
# Scan local image
trivy image my-app:latest
Example output:
nginx:1.25 (debian 12.5)
========================
Total: 127 (UNKNOWN: 0, LOW: 45, MEDIUM: 62, HIGH: 18, CRITICAL: 2)
Filter by Severity
# Only show HIGH and CRITICAL
trivy image --severity HIGH,CRITICAL nginx:1.25
# Only show vulnerabilities with fixes available
trivy image --ignore-unfixed nginx:1.25
Fail the Build on Vulnerabilities
# Exit code 1 if CRITICAL vulnerabilities found
trivy image --exit-code 1 --severity CRITICAL my-app:latest
# Use in a script
if ! trivy image --exit-code 1 --severity HIGH,CRITICAL my-app:latest; then
echo "Critical vulnerabilities found — blocking deployment"
exit 1
fi
Scanning Kubernetes
Scan a Whole Cluster
# Scan the cluster you're connected to
trivy k8s --report summary cluster
# Scan a specific namespace
trivy k8s -n production --report summary all
# Scan only for critical issues
trivy k8s --severity CRITICAL --report all cluster
Scan Kubernetes Manifests
# Scan YAML files before deploying
trivy config ./k8s/
# Scan a Helm chart
trivy config ./charts/my-app
Example findings Trivy detects:
HIGH ========= Container runs as root
MEDIUM ======== Missing resource limits
MEDIUM ======== Privileged container
HIGH ========= Hardcoded secret in env var
Filesystem and IaC Scanning
Scan a Git Repository
# Scan local directory for vulnerabilities + secrets
trivy fs .
# Only look for secrets
trivy fs --scanners secret .
# Scan a remote repo
trivy repo https://github.com/org/repo
Scan Terraform
trivy config ./terraform/
Findings include public S3 buckets, open security groups, unencrypted storage.
Scan a Dockerfile
trivy config Dockerfile
CI/CD Integration
GitHub Actions
name: Security Scan
on: [push]
jobs:
trivy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t my-app:${{ github.sha }} .
- name: Run Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: my-app:${{ github.sha }}
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH
exit-code: 1 # fail the pipeline
- name: Upload to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarif
Jenkins Pipeline
stage('Security Scan') {
steps {
sh '''
trivy image --exit-code 1 \
--severity HIGH,CRITICAL \
--format json -o trivy-report.json \
${DOCKER_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}
'''
}
post {
always {
archiveArtifacts artifacts: 'trivy-report.json'
}
}
}
GitLab CI
trivy-scan:
stage: test
image: aquasec/trivy:latest
script:
- trivy image --exit-code 1 --severity CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
allow_failure: false
Filtering and Reporting
Output Formats
# Table (default)
trivy image nginx:latest
# JSON for automation
trivy image --format json -o results.json nginx:latest
# SARIF for GitHub Security
trivy image --format sarif -o results.sarif nginx:latest
# CycloneDX SBOM
trivy image --format cyclonedx -o sbom.json nginx:latest
Ignore Specific CVEs
Create .trivyignore:
# .trivyignore
CVE-2023-12345 # not exploitable in our config
CVE-2024-99999 # waiting for upstream fix, expires 2025-01
trivy image --ignorefile .trivyignore my-app:latest
Scan for Secrets
# Find leaked credentials in files
trivy fs --scanners secret ./my-repo
# Scan an image's layers for secrets
trivy image --scanners secret my-app:latest
Practical DevSecOps Workflow
# 1. Before building: check dependencies
trivy fs .
# 2. After building: scan image
docker build -t my-app:1.0 .
trivy image --severity HIGH,CRITICAL --exit-code 1 my-app:1.0
# 3. Before deploying: scan manifests
trivy config ./k8s/
# 4. In production: periodic cluster scans
trivy k8s --report summary cluster
Useful Commands Reference
| Command | Purpose |
|---|---|
trivy image <name> | Scan container image |
trivy fs <path> | Scan filesystem/repo |
trivy config <path> | Scan IaC/manifests |
trivy k8s cluster | Scan Kubernetes cluster |
trivy repo <url> | Scan remote repository |
trivy sbom <file> | Scan SBOM file |
Best Practices
- Scan on every build — catch CVEs before they reach production
- Fail on CRITICAL only — HIGH noise can stall pipelines; tune gradually
- Maintain
.trivyignorewith justification comments and expiry notes - Scan images AND manifests — image CVEs and config misconfigurations are different problems
- Generate SBOMs — needed for compliance (e.g., supply chain audits)
- Scan base images too — most CVEs come from the base image, not your code
Related Articles
- DevSecOps Pipeline: Security in CI/CD
- Docker Security: Scanning and Hardening
- Kubernetes Secrets Management
Last Updated: October 2026
Author: CloudOpsGuide Team
Difficulty: Intermediate
Estimated Reading Time: 12 minutes