Scan Docker Container Images for Vulnerabilities with Trivy
Ever pulled an image from a registry and wondered if it’s hiding any nasty bugs or security holes? With Trivy you can get that answer in seconds, whether you’re running a quick local test or hunting through dozens of images in your CI pipeline.
Why you’ll need this
I’ve seen production failures after pulling a supposedly “latest” Alpine image that actually shipped with an unpatched glibc vulnerability. If that had been caught early, we’d have spent fewer hours chasing mysterious segmentation faults. Trivy turns those blind spots into red‑flag alerts so you can patch or replace before it’s too late.
Install Trivy
brew install aquasecurity/trivy/trivy # macOS sudo apt-get install -y trivy # Debian/Ubuntu
Why?
Trivy is a single binary, no Docker daemon needed. If you’re already on Linux and want the quickest route, use apt. On macOS Homebrew keeps it up to date automatically.
Scan an image locally
trivy image --exit-code 1 ubuntu:20.04
The --exit-code 1 flag makes Trivy return a non‑zero status if any vulnerability is found – handy for CI scripts that should fail fast.
Why not just view the report?
In a pipeline you want the build to abort on critical issues, not let them slip through and get buried in logs.
Narrow down what matters
trivy image --severity HIGH,CRITICAL alpine:3.16
Why specify severity?
Low‑impact bugs clutter reports. By filtering to only the high‑risk ones you keep your eyes on what truly needs a fix.
Scan a local Dockerfile build output
trivy image --no-progress $(docker build -q .)
The $(docker build -q .) trick captures the new image ID without printing the whole build log.
Why use it?
It lets you run a vulnerability check right after building, catching regressions from a recent dependency upgrade.
Integrate with GitHub Actions
# .github/workflows/trivy.yml
name: Scan
on: [push]
jobs:
trivy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Docker build
run: docker build -t myapp:$GITHUB_SHA .
- name: Trivy scan
run: |
trivy image --exit-code 0 \
--format template \
--template "@trivy.tpl" \
myapp:$GITHUB_SHA
Why skip --exit-code in CI?
Some teams prefer a non‑blocking scan that just produces a report. Set it back to 1 if you want the job to fail on any vulnerability.
Quick cheat sheet
| Command | What it does | Why it matters |
|---|---|---|
| trivy image | Scans an image | Core functionality |
| --severity HIGH,CRITICAL | Filters by risk level | Reduces noise |
| --exit-code 1 | Fails on any finding | Forces remediation |
| --no-progress | Suppresses progress bar | Keeps CI logs tidy |
Tips & pitfalls
- Cache issues – Trivy keeps a local cache of vulnerability data. If you’re getting stale results, run trivy --cache-clean or delete the cache folder (~/.cache/trivy).
- Custom CVE DBs – If your organization has its own CVE feed, point Trivy at it with --vuln-type os,library.
- Docker Hub vs. private registries – When pulling from a private registry you might need to authenticate first: docker login my.private.registry.
Final thought
Trivy is that low‑effort security check that actually saves time. If you’re not already scanning your images, the next build will probably surprise you with how many old packages are still floating around. Give it a whirl and keep those containers as clean as your code.