Trivy Tutorial: Scan Images, Code, and IaC
Trivy is the all-in-one open-source scanner for finding vulnerabilities, misconfigurations, and secrets across container images, code, and cloud infrastructure.
What is Trivy?
Trivy is an open-source security scanner maintained by Aqua Security. It started as a container image vulnerability scanner and has grown into a single tool that covers most of what a security or platform engineer needs to check before code is released: known CVEs in OS and language dependencies, infrastructure-as-code misconfigurations, hardcoded secrets, software bills of materials (SBOMs), and license problems.
What makes Trivy popular is its operational simplicity. It is a single statically linked binary with no daemon, no agent, and no account to create. You point it at a target - a container image, a directory, a git repo, a Kubernetes cluster - and it prints a report. That low friction is why it shows up in CI pipelines, in pre-commit hooks, and in ad-hoc terminal sessions.
How Trivy works (key concepts)
Trivy is organized around targets and scanners. The target is what you scan, selected by a subcommand: image, fs (filesystem), repo, config, k8s, and a few others. The scanners are what it looks for - vulnerabilities, misconfigurations, secrets, and licenses - and several of them can run in a single pass.
For vulnerability scanning, Trivy first builds an inventory of components in the target. For OS packages it reads the package database (apk, dpkg, rpm); for application dependencies it parses lockfiles and manifests such as package-lock.json, go.sum, Gemfile.lock, and requirements.txt. It then matches that inventory against its vulnerability database, a compiled bundle assembled from sources like the National Vulnerability Database and per-distro security advisories. That database is downloaded and cached locally on first run and refreshed automatically, so a fresh scan needs network access the first time but is fast afterward.
The config scanner is different in kind. Instead of matching packages against CVEs, it evaluates IaC files - Terraform, CloudFormation, Kubernetes manifests, Dockerfiles, Helm charts - against a library of built-in policies written as Rego rules. This is how Trivy flags things like a security group open to 0.0.0.0/0 or a container running as root. Note that the config subcommand only performs misconfiguration scanning, whereas image, fs, and repo can scan for vulnerabilities and secrets at the same time.
Two concepts matter for keeping output actionable. Severity ranks each finding as UNKNOWN, LOW, MEDIUM, HIGH, or CRITICAL, and you filter on it with --severity. Fix availability distinguishes vulnerabilities that have a patched version from those that do not; --ignore-unfixed hides the ones you cannot act on yet, which sharply reduces noise.
Installing Trivy
The quickest cross-platform method is the official install script, which fetches the right binary for your OS and architecture from GitHub Releases. As with any security tool you run in CI, read the script first, pin a specific Trivy version, and verify the release checksum or signature rather than always pulling the newest build:
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh \
| sudo sh -s -- -b /usr/local/bin
trivy --version
On Debian or Ubuntu you can use Aqua Security's apt repository so Trivy stays current through your normal package updates:
sudo apt-get install -y wget gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key \
| gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" \
| sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install -y trivy
On macOS, brew install trivy is the standard route. There is also an official aquasec/trivy container image if you prefer not to install anything locally.
Hands-on: scanning an image, a repo, and Terraform
Start with a container image. This pulls (if needed) and scans python:3.12-slim, then narrows the report to the findings worth acting on - high and critical severity, and only those with a fix available:
# Full report for an image
trivy image python:3.12-slim
# Only actionable findings: HIGH/CRITICAL with a patched version available
trivy image --severity HIGH,CRITICAL --ignore-unfixed python:3.12-slim
Next, scan source code on disk before it is ever built into an image. The fs target reads lockfiles for dependency CVEs and can detect committed secrets in the same pass:
# Scan the current directory for vulns and secrets
trivy fs --scanners vuln,secret .
Trivy also checks infrastructure-as-code. Point the config subcommand at a Terraform directory to evaluate it against the built-in misconfiguration policies:
trivy config --severity HIGH,CRITICAL ./infra
Finally, wire it into CI so a risky change fails the build instead of reaching production unnoticed. The --exit-code flag returns a non-zero status when matching vulnerabilities are found; --format json gives machine-readable output you can archive or feed into other tools:
trivy image \
--exit-code 1 \
--severity HIGH,CRITICAL \
--ignore-unfixed \
--format json \
--output trivy-report.json \
myorg/myapp:latest
If that command exits 1, the pipeline step fails and the report file captures exactly which CVEs triggered it. With no qualifying findings, Trivy exits 0 and the build proceeds. To suppress a specific finding you have triaged, list its ID in a .trivyignore file rather than weakening the severity gate for everyone.
When to use Trivy
Reach for Trivy whenever you need a fast, broad answer to "is there anything obviously dangerous in this artifact?" It is most useful in the container build pipeline, where it gates images before they reach a registry; the pull request, where trivy fs and trivy config catch vulnerable dependencies and IaC misconfigurations early; and incident response, where you scan a running image or cluster to map exposure to a freshly disclosed CVE.
It is less suited to deep application security testing. Trivy does not do dynamic analysis, fuzzing, or sophisticated dataflow-based SAST, so pair it with tools built for those jobs. As a broad, low-cost first check that covers dependencies, secrets, and misconfigurations in one binary, though, it is very effective - which is why it has become a standard part of so many DevSecOps toolchains.
Frequently asked questions
What is Trivy?
Trivy is an open-source security scanner from Aqua Security. It detects known vulnerabilities (CVEs), infrastructure-as-code misconfigurations, hardcoded secrets, and license issues across container images, filesystems, git repositories, and Kubernetes clusters. It runs as a single self-contained binary with no server required.
Is Trivy free?
Yes. Trivy is fully open-source under the Apache 2.0 license and free to use, including its vulnerability database. Aqua Security also sells a commercial platform (Aqua) that builds on Trivy, but the CLI scanner itself has no paid tier or feature gate.
What is the difference between trivy image and trivy fs?
trivy image scans a built container image (local or from a registry) by inspecting its layers and installed OS and language packages. trivy fs scans a directory on disk, which is useful for source repositories, lockfiles, and IaC files before an image is ever built. Both can detect vulnerabilities and secrets.
How do I make Trivy fail a CI build?
Use the --exit-code flag. Running trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest makes Trivy return a non-zero exit code when matching vulnerabilities are found, which fails the CI step. With no findings it exits 0 and the pipeline continues.
Do real production work, free. Live cloud workspaces in your browser - every project you complete lands on your portfolio.
Get started - free