← All posts

Tutorial DevOps

How to Scan a Docker Image for Vulnerabilities with Trivy

Scan Docker images for security vulnerabilities with Trivy and fix high-severity issues before deploying to production.

Difficulty Beginner Time 20 min
Trivy security scanner analyzing Docker container image layers for vulnerabilities

Container images often ship with vulnerable packages and outdated dependencies. In this tutorial, I will show you how to install Trivy, a popular open-source security scanner, and use it to scan Docker images for known vulnerabilities before deployment. By the end, you will be able to identify security issues, filter by severity, and integrate scanning into your build pipeline.

Prerequisites

  • A Linux or macOS machine with Docker installed and running
  • At least one Docker image available locally or on Docker Hub
  • Basic familiarity with Docker commands
  • Internet connection for downloading Trivy and vulnerability databases

Step 1 - Install Trivy

Trivy is a lightweight vulnerability scanner developed by Aqua Security. On Ubuntu or Debian, install it using the official repository:

sudo apt-get update sudo apt-get install wget apt-transport-https gnupg lsb-release -y wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add - echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list sudo apt-get update sudo apt-get install trivy -y

On macOS with Homebrew, install it with:

brew install trivy

On other Linux distributions, download the latest binary from the GitHub releases page and install it manually:

wget https://github.com/aquasecurity/trivy/releases/download/v0.48.0/trivy_0.48.0_Linux-64bit.tar.gz tar zxvf trivy_0.48.0_Linux-64bit.tar.gz sudo mv trivy /usr/local/bin/ sudo chmod +x /usr/local/bin/trivy

Verify the installation:

trivy --version

You should see the version number confirming Trivy is installed.

Step 2 - Pull or Build a Docker Image to Scan

For this tutorial, I will scan a common base image. Pull a sample image from Docker Hub:

docker pull nginx:latest

If you have your own application image, use that instead. List your local images:

docker images

Choose any image from the list to scan in the next step.

Step 3 - Run a Basic Trivy Scan

Scan the nginx image for vulnerabilities:

trivy image nginx:latest

Trivy will download its vulnerability database on the first run, then scan the image layers and list all detected vulnerabilities. The output shows each CVE with its severity, package name, installed version, and fixed version if available.

The scan results are grouped by severity: CRITICAL, HIGH, MEDIUM, LOW, and UNKNOWN. Pay close attention to CRITICAL and HIGH severity issues.

Step 4 - Filter Scan Results by Severity

To focus on the most important issues, filter results to show only CRITICAL and HIGH severity vulnerabilities:

trivy image --severity CRITICAL,HIGH nginx:latest

This narrows the output to actionable issues that should be fixed before deploying the image to production.

You can also filter to a single severity level:

trivy image --severity CRITICAL nginx:latest

Step 5 - Scan and Exit with a Non-Zero Code on Vulnerabilities

In a CI/CD pipeline, you want the build to fail if critical vulnerabilities are found. Use the exit-code flag:

trivy image --exit-code 1 --severity CRITICAL,HIGH nginx:latest

If any CRITICAL or HIGH vulnerabilities are found, Trivy exits with code 1, which will fail the pipeline step. If no vulnerabilities are found, it exits with code 0.

This is useful in automated workflows to enforce security policies.

Step 6 - Generate a Report in JSON or Table Format

For easier parsing or integration with other tools, export the scan results to JSON:

trivy image --format json --output scan-results.json nginx:latest

This creates a JSON file with the full scan report. You can send this file to a security dashboard, ticketing system, or log aggregator.

To output a clean table format to a file:

trivy image --format table --output scan-results.txt nginx:latest

Open the file to review the results offline.

Step 7 - Scan Your Own Application Image

Now scan an image from your own project. If you have an image tagged myapp:v1.0, run:

trivy image --severity CRITICAL,HIGH myapp:v1.0

Review the output. If vulnerabilities are found, note the affected packages and check if a newer base image or updated package versions are available.

For example, if the scan shows an outdated version of curl with a known CVE, rebuild your image with the latest packages by running apt-get update and apt-get upgrade in your Dockerfile.

Step 8 - Fix Vulnerabilities and Rescan

To fix vulnerabilities, update your Dockerfile. If your base image is outdated, switch to a newer tag:

FROM node:18-alpine

Alpine-based images are often smaller and have fewer packages, reducing the attack surface. Add these lines to ensure packages are current:

RUN apk update && apk upgrade

Rebuild your image:

docker build -t myapp:v1.1 .

Rescan the new image:

trivy image --severity CRITICAL,HIGH myapp:v1.1

Compare the results to the previous scan. The number of vulnerabilities should decrease.

Step 9 - Integrate Trivy into Your CI/CD Pipeline

Add Trivy to your build pipeline to automatically scan every new image. In a GitHub Actions workflow, add this step:

- name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: image-ref: myapp:latest format: table exit-code: 1 severity: CRITICAL,HIGH

In GitLab CI, add this job:

trivy_scan: image: aquasec/trivy:latest script: - trivy image --exit-code 1 --severity CRITICAL,HIGH $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

This ensures no image with critical vulnerabilities reaches production.

Wrap-up

You now know how to install Trivy, scan Docker images for vulnerabilities, filter results by severity, generate reports, and integrate scanning into CI/CD pipelines. Make Trivy part of your image build workflow to catch security issues early. Scan regularly, update base images, and patch vulnerable packages before deploying to production. Security scanning is not a one-time task but an ongoing practice that keeps your containers safe.