How to Scan Docker Images for Vulnerabilities with Trivy (Free, 5 Minutes)

Last month I pulled a random Node.js base image for a side project and ran Trivy against it out of curiosity. 47 CVEs. Twelve of them critical. The image had been on Docker Hub for two years with 10M+ pulls. Nobody checks these things.

If you’re running containers — homelab, production, doesn’t matter — you need a vulnerability scanner. I’ve tried Snyk, Grype, Docker Scout, and Trivy. Trivy wins for my workflow because it’s a single binary, no account required, and scans in seconds.

What Trivy Actually Does

Trivy is an open-source security scanner from Aqua Security. It checks container images, filesystems, git repos, and Kubernetes clusters against the NVD (National Vulnerability Database) and vendor-specific advisory feeds. It downloads its vulnerability DB on first run (~30MB) and updates it automatically.

The key thing: it checks every layer of your image. That old libssl in your base image from 2023? Trivy finds it. That npm package with a known prototype pollution bug? Found. Java Log4j still lurking somewhere? Found.

Install and First Scan

On any Linux box (or macOS with Homebrew):

# Linux
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin v0.50.0

# macOS
brew install trivy

# Verify
trivy --version

Your first scan takes about 30 seconds (DB download), subsequent scans take 3-8 seconds depending on image size:

# Scan any image
trivy image node:18-alpine

# Scan with only HIGH and CRITICAL
trivy image --severity HIGH,CRITICAL nginx:latest

# Scan a local Dockerfile build
docker build -t myapp:latest .
trivy image myapp:latest

Reading the Output

Here’s what a real scan looks like against node:18-bullseye (I ran this today):

node:18-bullseye (debian 11.9)
Total: 312 (UNKNOWN: 2, LOW: 186, MEDIUM: 87, HIGH: 31, CRITICAL: 6)

┌──────────────────┬────────────────┬──────────┬────────────────────┐
│ Library          │ Vulnerability  │ Severity │ Fixed Version      │
├──────────────────┼────────────────┼──────────┼────────────────────┤
│ libssl1.1        │ CVE-2024-0727  │ HIGH     │ 1.1.1w-0+deb11u2   │
│ zlib1g           │ CVE-2023-45853 │ CRITICAL │ 1:1.2.11.dfsg-2+d2 │
│ curl             │ CVE-2024-2398  │ HIGH     │ 7.74.0-1.3+deb11u  │
└──────────────────┴────────────────┴──────────┴────────────────────┘

The “Fixed Version” column tells you if there’s a patch available. If it says “No fix,” you either accept the risk or switch base images.

My Actual Workflow

I run Trivy in three places:

  1. CI pipeline — fail the build if any CRITICAL CVEs exist with a fix available
  2. Weekly cron on my homelab — scan all running containers, alert if new CVEs appeared
  3. Before pulling new images — quick sanity check

Here’s the cron script I use on my TrueNAS box:

#!/bin/bash
# scan-all-containers.sh
RESULTS=""
for img in $(docker ps --format '{{.Image}}' | sort -u); do
  OUTPUT=$(trivy image --severity HIGH,CRITICAL --quiet "$img" 2>/dev/null)
  if [ -n "$OUTPUT" ]; then
    RESULTS+="\n=== $img ===\n$OUTPUT\n"
  fi
done

if [ -n "$RESULTS" ]; then
  curl -d "Container vulnerabilities found: $RESULTS" ntfy.sh/my-alerts
fi

Alpine vs Debian vs Distroless: The Numbers

I scanned the same Node.js app with three base images. Results from May 2026:

Base Image Size Total CVEs Critical High
node:18-bullseye 987MB 312 6 31
node:18-alpine 177MB 4 0 1
gcr.io/distroless/nodejs18 118MB 0 0 0

The pattern is clear: smaller image = fewer packages = fewer vulnerabilities. I switched everything I could to Alpine two years ago, and my scan noise dropped by 95%. Distroless is even better if you don’t need a shell for debugging.

CI Integration (GitHub Actions)

- name: Run Trivy vulnerability scanner
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: 'myapp:${{ github.sha }}'
    format: 'sarif'
    output: 'trivy-results.sarif'
    severity: 'CRITICAL,HIGH'
    exit-code: '1'

The exit-code: 1 means your build fails if vulnerabilities are found. The SARIF output integrates with GitHub’s Security tab so you can track issues over time.

Things That Surprised Me

A few gotchas after running Trivy for 18 months:

  • Official images aren’t safe. The “official” Python, Node, and Ruby images on Docker Hub often ship with dozens of known CVEs. The maintainers can’t rebuild fast enough.
  • Alpine’s musl libc is a trade-off. Fewer CVEs but occasional compatibility issues with native Node modules. Test your app.
  • False positives exist. Some CVEs in libraries aren’t exploitable in your context. Use .trivyignore to suppress known-safe findings.
  • The DB update matters. If your CI caches the Trivy DB too aggressively, you’ll miss new CVEs. I refresh weekly minimum.

Alternatives I’ve Tried

Grype (by Anchore) — similar speed, slightly different DB sources. Good second opinion but I prefer Trivy’s broader scanning scope (it does IaC too).

Docker Scout — built into Docker Desktop now. Convenient but requires a Docker account and only works with Docker images (no filesystem scanning).

Snyk Container — excellent fix suggestions but free tier is limited to 200 scans/month. For a homelab with 30+ containers, that burns fast.

Getting Started Today

Install Trivy, scan your most critical container, and see what falls out. I guarantee you’ll find something you didn’t know about. If you’re running a homelab, the weekly cron approach catches drift before it becomes a problem.

For monitoring your homelab network alongside container security, a good network switch with VLAN support helps isolate container traffic. I use a TP-Link managed switch (affiliate link) to segment my container host from IoT devices — one compromised container shouldn’t reach my cameras.

If you’re running regex-based security checks in your code, check out our regex security patterns post — handy for validating input sanitization patterns. And if you’re handling untrusted documents in your pipeline, Dangerzone is worth a look.

Join Alpha Signal for free market intelligence — we track tech infrastructure trends alongside trading signals.

📧 Get weekly insights on security, trading, and tech. No spam, unsubscribe anytime.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Also by us: StartCaaS — AI Company OS · Hype2You — AI Tech Trends