Fix Docker Vulnerabilities: Integrating Trivy in CI/CD Pipelines
Stop shipping insecure images. Learn how to fix Docker vulnerabilities by integrating the Trivy scanner into your CI/CD pipeline for automated security.
We’ve all been there: you push a container to production, only for a security scan to flag a critical CVE in a base image you thought was "stable." It’s a sinking feeling. You realize your current workflow is reactive—you’re finding bugs after they’re already in your registry.
If you want to actually fix docker vulnerabilities rather than just patching them during an incident, you need to move the security gate to the left. Integrating a trivy scanner into your automated pipelines is the most reliable way to catch these issues before they reach your production environment.
Why Trivy is the industry standard
There are plenty of tools out there, but Trivy has become my go-to because it’s incredibly fast and covers more than just OS packages. It scans your filesystem, language-specific dependencies (like package-lock.json or requirements.txt), and even your Infrastructure as Code (IaC) files.
When I first started using it, I tried running it manually on my laptop. That’s fine for a quick check, but it’s not a strategy. True docker security comes from consistency. If the scan isn't part of your build process, it doesn't exist.
Integrating Trivy into GitHub Actions
Automating container vulnerability scanning is surprisingly straightforward. If you’re using GitHub Actions, you don’t need to manage a complex security server. You can drop a scanning step directly into your workflow.
Here is how I typically structure the security job in a standard CI pipeline:
YAMLjobs: scan: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Build the Docker image run: docker build -t my-app:latest . - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: image-ref: 'my-app:latest' format: 'table' exit-code: '1' ignore-unfixed: true severity: 'CRITICAL,HIGH'
The "Gotchas" of Automated Scanning
Setting the exit-code: '1' is the most important line here. By default, Trivy will just report findings and let the build pass. By forcing a non-zero exit code, you ensure the CI pipeline fails if a critical vulnerability is detected.
However, be prepared for noise. When you first turn this on, you might get flooded with alerts for vulnerabilities that don't have a fix available yet. That’s why I set ignore-unfixed: true. It keeps the developers focused on the things they can actually patch right now.
Comparing Security Scanning Approaches
| Feature | Manual Scanning | CI/CD Integration (Trivy) |
|---|---|---|
| Consistency | Low (Human-dependent) | High (Automated) |
| Feedback Loop | Slow (Post-deployment) | Instant (During build) |
| Effort | High | Low (Set once) |
| Security Posture | Reactive | Proactive |
Moving beyond simple scans
Scanning is only half the battle. If you're still using massive, bloated base images, you're just inviting more vulnerabilities. I always recommend using Docker Multi-Stage Builds: Reduce Image Size and Harden Security to strip away build-time dependencies that attackers love to exploit.
Also, remember that even a clean image can be dangerous if your configuration is wrong. I've seen teams pass security audits but still expose their databases to the public internet because of bad docker-compose port bindings. Tools like Trivy are great, but they aren't a replacement for CI/CD Pipeline & Docker Containerization best practices.
What happens when you find a "Critical"?
When Trivy reports a vulnerability, don't panic. First, check if the package is even used in your production path. If it is, update your base image. If you're using a distroless base, you've already won half the battle by removing shells and package managers.
If you find yourself constantly fighting vulnerabilities, you might need to audit your base images. I've spent about two days before just migrating a legacy project from ubuntu:latest to alpine or distroless to cut down my scan results by roughly 60%.
FAQ
Does Trivy catch everything?
No. As noted in recent research, even top-tier scanners like Trivy, Checkov, and Semgrep often miss specific IaC misconfigurations, like insecure port bindings in docker-compose.yml. Always supplement automated scanning with manual code reviews.
How do I handle false positives?
Trivy allows you to use a .trivyignore file. If you’ve verified a vulnerability is a false positive or is mitigated by your application logic, add the CVE ID to that file to keep your CI logs clean.
Should I scan every single build? Yes. It adds about 20-30 seconds to the build time, which is a small price to pay for the peace of mind that you aren't shipping a known CVE.
Next time, I'd like to look into how we can automate the patching process using dependabot-style tools for Docker images. We’re getting better at detecting these issues, but the manual work of updating base tags is still a chore that I'd love to eliminate.

