In my experience building production-grade Kubernetes clusters, the biggest blind spot is almost always the container image. We spend weeks hardening the network but then deploy a ‘latest’ tag image containing three critical CVEs. That is why I’ve integrated Trivy into every single one of my workflows. If you are looking for a step-by-step trivy container scanning guide, you’ve come to the right place.
Trivy, developed by Aqua Security, has become my go-to because it’s incredibly fast and doesn’t require a complex database setup to get started. Whether you are comparing it against other best open source container security scanners or just starting with DevSecOps, getting a handle on your image vulnerabilities is non-negotiable.
Prerequisites
Before we dive into the scanning process, ensure you have the following installed on your machine:
- Docker: Installed and running (Trivy scans images stored in your local Docker daemon or remote registries).
- Curl: Needed for the installation script.
- A Linux or macOS environment: While Windows is supported via WSL2, I highly recommend a Unix-like shell for the best experience.
Step 1: Installing Trivy
I prefer using the official installation script because it handles the binary placement perfectly. Run the following command in your terminal:
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
Once installed, verify that the binary is accessible by checking the version:
trivy --version
Step 2: Running Your First Container Scan
The beauty of Trivy is its simplicity. You don’t need a config file for a basic scan. To scan a public image (e.g., Nginx), use the image command. As shown in the image below, the output will categorize vulnerabilities by severity.
trivy image nginx:latest
When I run this, Trivy downloads the vulnerability database from GitHub (the first run takes a few seconds longer) and then analyzes the OS packages and language-specific dependencies within the image.
Step 3: Filtering for Critical Vulnerabilities
In a real-world project, a standard scan can return hundreds of ‘Low’ or ‘Medium’ vulnerabilities that you might not have the bandwidth to fix immediately. To keep your signal-to-noise ratio high, I always filter for HIGH and CRITICAL levels.
trivy image --severity HIGH,CRITICAL nginx:latest
This allows you to focus on the flaws that actually pose a risk to your infrastructure. If you’re also managing your infrastructure as code, you might want to pair this with automating IaC security with Checkov to ensure your deployment manifests are just as secure as your images.
Step 4: Generating Machine-Readable Reports
If you are integrating this into a dashboard or a security audit, raw terminal output isn’t enough. Trivy supports JSON and Template formats. I personally use JSON for automation scripts.
trivy image -f json -o results.json nginx:latest
Step 5: Integrating Trivy into GitHub Actions
Manually running scans is a recipe for failure—you’ll eventually forget. I’ve automated my scanning using the official Trivy GitHub Action. Here is a snippet of how I set up my workflow file:
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'my-app:${{ github.sha }}
format: 'table'
exit-code: '1' # This fails the build if vulnerabilities are found
severity: 'CRITICAL,HIGH'
Setting exit-code: '1' is a power move. It effectively turns your security scan into a quality gate, preventing vulnerable code from ever reaching your registry.
Pro Tips for Better Scanning
- Use .trivyignore: Sometimes a vulnerability is a false positive or has no available fix. Create a
.trivyignorefile in your root directory to silence these specific CVE IDs. - Scan Filesystems: Trivy isn’t just for images. Use
trivy fs /path/to/projectto scan your local source code for hardcoded secrets and vulnerable dependencies. - Client-Server Mode: If you have a massive CI/CD pipeline, don’t download the DB on every runner. Run Trivy in server mode and let your clients query it to save time and bandwidth.
Troubleshooting Common Issues
Issue: “Failed to download vulnerability database”
Solution: This is usually a network or proxy issue. Ensure your environment has access to github.com. If you are behind a strict corporate proxy, set the HTTP_PROXY environment variable before running the scan.
Issue: “Unable to find image locally”
Solution: If you are scanning a private image, make sure you have performed a docker login to the registry first. Trivy uses your local Docker credentials to pull the image.
What’s Next?
Now that you have a working container scanning pipeline, the next step is remediation. Don’t just find bugs—fix them. Start by switching to Distroless images or Alpine Linux to reduce the attack surface. Reducing the number of installed packages is the most effective way to reduce the number of CVEs Trivy finds.
If you’re looking for more ways to harden your stack, I recommend checking out my other guides on container security tools and IaC automation.