CloudOpsGuide
devsecops

Trivy: Container Image Scanning Guide

Intermediate
12 minutes
October 2026
CloudOpsGuide Team

Trivy: Container Image Scanning Guide

Scan Docker images, Kubernetes clusters, filesystems, and IaC for vulnerabilities and misconfigurations with Trivy — the industry-standard open-source scanner.

Table of Contents

What is Trivy

Trivy is an open-source vulnerability scanner by Aqua Security that detects:

  • OS package vulnerabilities (Alpine, Debian, RHEL, etc.)
  • Language dependency vulnerabilities (npm, pip, Go modules, Maven...)
  • Misconfigurations in Kubernetes, Terraform, Dockerfiles
  • Secrets accidentally committed (API keys, passwords)
  • License compliance issues

Installation

# macOS
brew install trivy

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

# Docker (no install needed)
docker run --rm aquasec/trivy:latest image nginx:latest

# Verify
trivy version

Scanning Container Images

Basic Scan

# Scan an image
trivy image nginx:1.25

# Scan local image
trivy image my-app:latest

Example output:

nginx:1.25 (debian 12.5)
========================
Total: 127 (UNKNOWN: 0, LOW: 45, MEDIUM: 62, HIGH: 18, CRITICAL: 2)

Filter by Severity

# Only show HIGH and CRITICAL
trivy image --severity HIGH,CRITICAL nginx:1.25

# Only show vulnerabilities with fixes available
trivy image --ignore-unfixed nginx:1.25

Fail the Build on Vulnerabilities

# Exit code 1 if CRITICAL vulnerabilities found
trivy image --exit-code 1 --severity CRITICAL my-app:latest

# Use in a script
if ! trivy image --exit-code 1 --severity HIGH,CRITICAL my-app:latest; then
  echo "Critical vulnerabilities found — blocking deployment"
  exit 1
fi

Scanning Kubernetes

Scan a Whole Cluster

# Scan the cluster you're connected to
trivy k8s --report summary cluster

# Scan a specific namespace
trivy k8s -n production --report summary all

# Scan only for critical issues
trivy k8s --severity CRITICAL --report all cluster

Scan Kubernetes Manifests

# Scan YAML files before deploying
trivy config ./k8s/

# Scan a Helm chart
trivy config ./charts/my-app

Example findings Trivy detects:

HIGH  =========  Container runs as root
MEDIUM ========  Missing resource limits
MEDIUM ========  Privileged container
HIGH  =========  Hardcoded secret in env var

Filesystem and IaC Scanning

Scan a Git Repository

# Scan local directory for vulnerabilities + secrets
trivy fs .

# Only look for secrets
trivy fs --scanners secret .

# Scan a remote repo
trivy repo https://github.com/org/repo

Scan Terraform

trivy config ./terraform/

Findings include public S3 buckets, open security groups, unencrypted storage.

Scan a Dockerfile

trivy config Dockerfile

CI/CD Integration

GitHub Actions

name: Security Scan
on: [push]

jobs:
  trivy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build image
        run: docker build -t my-app:${{ github.sha }} .

      - name: Run Trivy
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: my-app:${{ github.sha }}
          format: sarif
          output: trivy-results.sarif
          severity: CRITICAL,HIGH
          exit-code: 1    # fail the pipeline

      - name: Upload to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy-results.sarif

Jenkins Pipeline

stage('Security Scan') {
    steps {
        sh '''
            trivy image --exit-code 1 \
              --severity HIGH,CRITICAL \
              --format json -o trivy-report.json \
              ${DOCKER_REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}
        '''
    }
    post {
        always {
            archiveArtifacts artifacts: 'trivy-report.json'
        }
    }
}

GitLab CI

trivy-scan:
  stage: test
  image: aquasec/trivy:latest
  script:
    - trivy image --exit-code 1 --severity CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  allow_failure: false

Filtering and Reporting

Output Formats

# Table (default)
trivy image nginx:latest

# JSON for automation
trivy image --format json -o results.json nginx:latest

# SARIF for GitHub Security
trivy image --format sarif -o results.sarif nginx:latest

# CycloneDX SBOM
trivy image --format cyclonedx -o sbom.json nginx:latest

Ignore Specific CVEs

Create .trivyignore:

# .trivyignore
CVE-2023-12345   # not exploitable in our config
CVE-2024-99999   # waiting for upstream fix, expires 2025-01
trivy image --ignorefile .trivyignore my-app:latest

Scan for Secrets

# Find leaked credentials in files
trivy fs --scanners secret ./my-repo

# Scan an image's layers for secrets
trivy image --scanners secret my-app:latest

Practical DevSecOps Workflow

# 1. Before building: check dependencies
trivy fs .

# 2. After building: scan image
docker build -t my-app:1.0 .
trivy image --severity HIGH,CRITICAL --exit-code 1 my-app:1.0

# 3. Before deploying: scan manifests
trivy config ./k8s/

# 4. In production: periodic cluster scans
trivy k8s --report summary cluster

Useful Commands Reference

CommandPurpose
trivy image <name>Scan container image
trivy fs <path>Scan filesystem/repo
trivy config <path>Scan IaC/manifests
trivy k8s clusterScan Kubernetes cluster
trivy repo <url>Scan remote repository
trivy sbom <file>Scan SBOM file

Best Practices

  1. Scan on every build — catch CVEs before they reach production
  2. Fail on CRITICAL only — HIGH noise can stall pipelines; tune gradually
  3. Maintain .trivyignore with justification comments and expiry notes
  4. Scan images AND manifests — image CVEs and config misconfigurations are different problems
  5. Generate SBOMs — needed for compliance (e.g., supply chain audits)
  6. Scan base images too — most CVEs come from the base image, not your code

Related Articles


Last Updated: October 2026
Author: CloudOpsGuide Team
Difficulty: Intermediate
Estimated Reading Time: 12 minutes