Trivy (pronounced “tri-vee”, short for “Triple Vee” / vulnerability, misconfiguration, secret) is an open-source, all-in-one security scanner developed by Aqua Security. It is one of the most widely adopted container and software supply-chain security tools because a single binary can scan:
- Container images (Docker, OCI) for OS package and application-dependency vulnerabilities.
- Filesystems and local directories for the same, plus embedded secrets.
- Git repositories (remote or local) for vulnerabilities and misconfigurations.
- Infrastructure-as-Code files (Terraform, CloudFormation, Kubernetes manifests, Dockerfiles, Helm charts) for misconfigurations.
- Kubernetes clusters directly, scanning live workloads.
- SBOMs (Software Bill of Materials) in CycloneDX and SPDX formats, both generating and scanning them.
- License information for dependencies.
- Secrets such as API keys, tokens, and private keys accidentally baked into images or code.
Trivy is fast because it caches vulnerability databases locally and uses efficient layer analysis, and it is accurate because it pulls from multiple upstream vulnerability sources (NVD, GitHub Security Advisories, distro-specific advisories such as Debian DSA, Red Hat OVAL, Alpine SecDB, etc.).
Installation
Method 1 – APT repository (recommended for Kali/Debian-based systems):
sudo apt-get install wget apt-transport-https gnupg lsb-release -y
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo gpg --dearmor -o /usr/share/keyrings/trivy.gpg
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy -y
Method 2 – Install script:
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin
Method 3 – Binary download from GitHub releases:
wget https://github.com/aquasecurity/trivy/releases/download/v0.55.2/trivy_0.55.2_Linux-64bit.deb
sudo dpkg -i trivy_0.55.2_Linux-64bit.deb
Method 4 – Docker (no local install):
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image alpine:3.19
Verify installation:
trivy --version
Expected output:
Version: 0.55.2
Vulnerability DB:
Version: 2
UpdatedAt: 2026-07-18 06:12:31.123456789 +0000 UTC
NextUpdate: 2026-07-19 06:12:31.123456789 +0000 UTC
DownloadedAt: 2026-07-18 09:04:11.987654321 +0000 UTC
Syntax
trivy [global options] command [command options] [target]
General command form:
trivy <SCAN_TYPE> [FLAGS] <TARGET>
Where <SCAN_TYPE> is one of: image, fs, rootfs, repository, kubernetes, sbom, config, secret, vm, plugin.
Command-Line Options (Full Reference)
Top-level commands:
| Command | Purpose |
|---|---|
trivy image | Scan a container image |
trivy fs | Scan a filesystem/directory |
trivy rootfs | Scan a mounted root filesystem |
trivy repository | Scan a remote/local Git repository |
trivy kubernetes | Scan a live Kubernetes cluster |
trivy config | Scan IaC config files for misconfigurations |
trivy sbom | Scan an existing SBOM file |
trivy vm | Scan a virtual machine image |
trivy plugin | Manage Trivy plugins |
trivy server | Run Trivy in client/server mode |
trivy module | Manage Trivy modules |
trivy clean | Remove cached data |
Global flags:
| Flag | Description |
|---|---|
-q, --quiet | Suppress non-essential output |
-d, --debug | Enable debug logging |
--cache-dir | Set cache directory path |
--config | Specify a config file (trivy.yaml) |
-v, --version | Print version |
-h, --help | Show help |
--timeout | Set scan timeout (default 5m) |
--insecure | Allow insecure server connections |
Scan-specific flags (apply to image, fs, repository, etc.):
| Flag | Description |
|---|---|
--severity | Filter by severity: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL |
--vuln-type | Filter: os, library, or both |
--scanners | Choose scanners: vuln, misconfig, secret, license |
--format, -f | Output format: table, json, sarif, cyclonedx, spdx, spdx-json, github, template |
--output, -o | Write results to a file |
--exit-code | Exit code to use when vulnerabilities found (e.g. 1) |
--ignore-unfixed | Skip vulnerabilities without a known fix |
--ignorefile | Path to .trivyignore file |
--skip-dirs | Comma-separated dirs to skip |
--skip-files | Comma-separated files to skip |
--no-progress | Suppress progress bar |
--offline-scan | Scan without contacting external servers |
--list-all-pkgs | List all packages, not just vulnerable ones |
--input | Scan a .tar image saved with docker save |
--platform | Specify platform for multi-arch images (e.g. linux/arm64) |
--db-repository | Custom vulnerability DB OCI repository |
--skip-db-update | Skip vuln DB update before scanning |
--reset | Remove cache and DB, then re-download |
--username / --password | Registry credentials |
--secret-config | Custom path for secret detection rules |
--compliance | Run a compliance report (e.g. docker-cis, k8s-cis) |
trivy k8s specific flags:
| Flag | Description |
|---|---|
--report | summary or all |
--namespace | Scan specific namespace only |
--kubeconfig | Path to kubeconfig file |
--include-namespaces | Comma-separated list to include |
--exclude-namespaces | Comma-separated list to exclude |
--compliance | e.g. k8s-cis, k8s-nsa, k8s-pss-baseline, k8s-pss-restricted |
Basic Usage
Scan a public image with default settings:
trivy image nginx:1.25
Expected output (truncated):
2026-07-19T10:02:11.001+0500 INFO Vulnerability scanning is enabled
2026-07-19T10:02:11.002+0500 INFO Detected OS: debian
2026-07-19T10:02:11.003+0500 INFO Detecting Debian vulnerabilities...
2026-07-19T10:02:12.512+0500 INFO Number of language-specific files: 1
nginx:1.25 (debian 12.5)
=========================
Total: 84 (UNKNOWN: 0, LOW: 40, MEDIUM: 22, HIGH: 18, CRITICAL: 4)
┌───────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬──────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
├───────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼──────────────────────────────────────────┤
│ libssl3 │ CVE-2024-0727 │ CRITICAL │ fixed │ 3.0.11-1~deb12u2 │ 3.0.13-1 │ openssl: PKCS12 Decoding crashes │
│ libc-bin │ CVE-2023-4911 │ HIGH │ fixed │ 2.36-9 │ 2.36-9+deb12u3│ glibc: buffer overflow in ld.so │
└───────────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴──────────────────────────────────────────┘
Practical Examples with Output
Example 1 – Scan and show only HIGH/CRITICAL severities:
trivy image --severity HIGH,CRITICAL alpine:3.18
alpine:3.18 (alpine 3.18.4)
============================
Total: 3 (HIGH: 2, CRITICAL: 1)
┌─────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬─────────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
├─────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼─────────────────────────┤
│ openssl │ CVE-2024-13176 │ CRITICAL │ fixed │ 3.1.4-r5 │ 3.1.5-r0 │ openssl: timing side-ch. │
│ busybox │ CVE-2023-42364 │ HIGH │ fixed │ 1.36.1-r2 │ 1.36.1-r5 │ busybox: OOB read │
└─────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴─────────────────────────┘
Example 2 – Scan a local Dockerfile for misconfigurations:
trivy config ./Dockerfile
./Dockerfile (dockerfile)
==========================
Tests: 24 (SUCCESSES: 20, FAILURES: 4, EXCEPTIONS: 0)
Failures: 4 (UNKNOWN: 0, LOW: 1, MEDIUM: 2, HIGH: 1, CRITICAL: 0)
DS002 (HIGH): Image user should not be 'root'
════════════════════════════════════════════
Last USER should not be root
────────────────────────────────────────────
Dockerfile:1
────────────────────────────────────────────
1 [ FROM ubuntu:22.04
────────────────────────────────────────────
Example 3 – Scan filesystem/project directory including secrets:
trivy fs --scanners vuln,secret,misconfig ./my-app
2026-07-19T10:11:04.221+0500 INFO Number of language-specific files: 3
my-app/requirements.txt (pip)
==============================
Total: 2 (HIGH: 1, CRITICAL: 1)
my-app/.env (secrets)
======================
Total: 1 (CRITICAL: 1)
┌─────────┬───────────────────┬──────────┬─────────────────────────────────┐
│ Rule │ Category │ Severity │ Match │
├─────────┼───────────────────┼──────────┼─────────────────────────────────┤
│ AWS-001 │ AWS Access Key ID │ CRITICAL │ AKIA**************** │
└─────────┴───────────────────┴──────────┴─────────────────────────────────┘
Example 4 – Scan a Git repository directly (no clone needed):
trivy repository https://github.com/example/vulnerable-app --severity CRITICAL
2026-07-19T10:14:33.100+0500 INFO Cloning https://github.com/example/vulnerable-app...
vulnerable-app (package-lock.json)
====================================
Total: 5 (CRITICAL: 5)
Example 5 – Output results in JSON to a file:
trivy image --format json --output result.json redis:7.2
cat result.json | head -n 15
{
"SchemaVersion": 2,
"ArtifactName": "redis:7.2",
"ArtifactType": "container_image",
"Metadata": {
"OS": {
"Family": "debian",
"Name": "12.5"
}
},
"Results": [
{
"Target": "redis:7.2 (debian 12.5)",
"Class": "os-pkgs",
"Type": "debian"
Example 6 – Ignore vulnerabilities without a fix, exit non-zero on CRITICAL:
trivy image --ignore-unfixed --severity CRITICAL --exit-code 1 myapp:latest
echo "Exit code: $?"
myapp:latest (debian 12.5)
============================
Total: 1 (CRITICAL: 1)
...
Exit code: 1
Example 7 – Scan an offline/air-gapped tarball image:
docker save myapp:latest -o myapp.tar
trivy image --input myapp.tar
2026-07-19T10:22:01.884+0500 INFO Loading myapp.tar
myapp.tar (alpine 3.19.1)
==========================
Total: 6 (LOW: 4, MEDIUM: 2)
Example 8 – Scan a live Kubernetes cluster namespace:
trivy kubernetes --namespace production --report summary
Summary Report for production
===============================
┌───────────┬──────────────┬────────┬─────────┬────────┬───────┬──────────┐
│ Namespace │ Resource │ Vulns │ Misconf │ Secret │ RBAC │ Overall │
├───────────┼──────────────┼────────┼─────────┼────────┼───────┼──────────┤
│production │ Deployment/web│ 14 (2C)│ 3 │ 0 │ - │ FAIL │
└───────────┴──────────────┴────────┴─────────┴────────┴───────┴──────────┘
Example 9 – Generate an SBOM in CycloneDX format:
trivy image --format cyclonedx --output sbom.json nginx:1.25
2026-07-19T10:27:44.301+0500 INFO Generating CycloneDX SBOM...
2026-07-19T10:27:45.902+0500 INFO SBOM written to sbom.json
Example 10 – Use a .trivyignore file to suppress known false positives:
cat .trivyignore
# Ignore this specific CVE - accepted risk
CVE-2023-1234
trivy image --ignorefile .trivyignore myapp:latest
myapp:latest (alpine 3.19.1)
==============================
Total: 5 (was 6, 1 ignored via .trivyignore)
Example 11 – Run a CIS Docker Compliance report:
trivy image --compliance docker-cis myapp:latest
Docker CIS 1.6.0 Compliance Report
====================================
┌────────┬───────────────────────────────┬────────┐
│ ID │ Title │ Status │
├────────┼───────────────────────────────┼────────┤
│ 5.6 │ Root user should not be used │ FAIL │
│ 5.10 │ Memory usage should be limited │ PASS │
└────────┴───────────────────────────────┴────────┘
Example 12 – Scan multiple images in a loop and export CSV summary:
for img in nginx:1.25 redis:7.2 alpine:3.19; do
count=$(trivy image --severity CRITICAL --format json "$img" | jq '[.Results[]?.Vulnerabilities[]?] | length')
echo "$img,$count" >> summary.csv
done
cat summary.csv
nginx:1.25,4
redis:7.2,1
alpine:3.19,1
Common Use Cases
- CI/CD pipeline gating – fail a build if CRITICAL vulnerabilities without a fix are found.
- Registry scanning – periodically scan every image in a private registry for drift.
- Pre-deployment gate – scan Kubernetes manifests/Helm charts with
trivy configbeforekubectl apply. - Supply-chain auditing – generate SBOMs for every release artifact and archive them for compliance.
- Secret leak detection – scan repositories and images before publishing to catch hard-coded credentials.
- Compliance reporting – run
--compliance docker-cisork8s-cisreports for auditors.
Automation with Bash
#!/usr/bin/env bash
# trivy-ci-gate.sh - Fail CI build on CRITICAL vulnerabilities with a fix available
set -euo pipefail
IMAGE="$1"
REPORT_DIR="./trivy-reports"
mkdir -p "$REPORT_DIR"
echo "[*] Updating Trivy DB..."
trivy image --download-db-only
echo "[*] Scanning $IMAGE ..."
trivy image \
--severity CRITICAL,HIGH \
--ignore-unfixed \
--exit-code 1 \
--format json \
--output "$REPORT_DIR/$(echo "$IMAGE" | tr '/:' '_').json" \
"$IMAGE"
STATUS=$?
if [ "$STATUS" -ne 0 ]; then
echo "[!] Build blocked: CRITICAL/HIGH vulnerabilities found in $IMAGE"
exit 1
fi
echo "[+] $IMAGE passed the security gate."
Run it:
chmod +x trivy-ci-gate.sh
./trivy-ci-gate.sh myapp:latest
Tips and Best Practices
- Run
trivy image --download-db-onlyon a schedule (cron) so scans stay fast and offline-capable. - Always combine
--ignore-unfixedwith CI gating — blocking builds for vulnerabilities with no available fix creates noise without actionable remediation. - Use
--scanners vuln,misconfig,secrettogether onfs/repositorytargets for full-spectrum coverage in one pass. - Store
.trivyignorefiles in version control with comments explaining why each CVE is suppressed, and set expiry review dates. - In air-gapped environments, mirror the vulnerability DB using
trivy --cache-dirandoras/skopeoto move the OCI DB artifact. - Prefer
--format jsonpiped tojqfor machine-parseable pipeline decisions rather than parsing table output. - Pin the Trivy version in CI to avoid unexpected new checks silently breaking existing pipelines.
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
unable to open GOB file cache error | Corrupted local cache | Run trivy clean --all and rescan |
| Scan hangs on DB download | Firewall blocking GitHub Container Registry | Set --skip-db-update and pre-seed cache, or allow ghcr.io |
permission denied scanning Docker socket | User not in docker group | sudo usermod -aG docker $USER and re-login |
| Rate limit errors pulling DB | GitHub API rate limiting | Set GITHUB_TOKEN env var to authenticate DB pulls |
| No vulnerabilities found on known-bad image | Wrong --vuln-type filter | Remove filter or set --vuln-type os,library |
context deadline exceeded | Default 5m timeout too short for large images | Increase with --timeout 15m |
References
- Official documentation: https://aquasecurity.github.io/trivy/
- GitHub repository: https://github.com/aquasecurity/trivy
- Vulnerability DB source: https://github.com/aquasecurity/trivy-db
- Aqua Security blog: https://www.aquasec.com/blog/
