Blog post image for Container Image Vulnerability Scanning in CI/CD with Trivy - Learn how to automate container image vulnerability scanning in your CI/CD pipeline using Trivy. This guide covers setup, integration strategies, policy enforcement, and remediation workflows to secure your container supply chain.

Container Image Vulnerability Scanning in CI/CD with Trivy

04 Mins read

Why Container Security Matters

The Vulnerability Problem

Container images are a critical attack surface in modern deployments.

Every time you build a container image, it includes the base OS layer, runtime libraries, dependencies, and your application code. Each layer can contain known vulnerabilities. Without scanning, vulnerable images reach production and expose your infrastructure to attacks.

Real Statistics

  • 80% of container images in production contain at least one known vulnerability
  • Supply chain attacks targeting container registries are increasing
  • Unpatched container vulnerabilities lead to data breaches and service disruptions

The Security Challenge

Why Manual Scanning Isn’t Enough

Manual security reviews don’t scale. You can’t realistically inspect every dependency in every container layer. Without automation, vulnerable images slip through, and by the time they’re discovered in production, the damage is already done.

Common Vulnerabilities in Containers

  • Outdated base images with unpatched OS vulnerabilities
  • Vulnerable dependencies from npm, pip, pip, Maven packages
  • Exposed secrets accidentally included in image layers
  • Misconfigurations creating insecure defaults
  • Malware hidden in supply chain attacks

The Solution: Trivy

What is Trivy?

Trivy is a simple, fast, and comprehensive container vulnerability scanner created by Aqua Security. It scans container images, filesystems, and configuration files for vulnerabilities, misconfigurations, and secrets.

Why Choose Trivy?

  • Speed: Scans images in seconds, not minutes
  • Accuracy: Supports multiple vulnerability databases (NVD, GitHub Security, Aqua, Alpine)
  • Comprehensive: Detects OS vulnerabilities, application dependencies, and misconfigurations
  • Zero setup: Works out of the box without complex configuration
  • CI/CD ready: Integrates easily into GitHub Actions, GitLab CI, Jenkins
  • Open-source: Free, transparent, and community-driven

Installation and Setup

Install Trivy

Terminal window
# macOS
brew install trivy
# Linux (Ubuntu/Debian)
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | apt-key add -
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | tee -a /etc/apt/sources.list.d/trivy.list
apt-get update
apt-get install trivy
# Docker
docker pull aquasec/trivy

Basic Image Scanning

Terminal window
# Scan a local image
trivy image my-app:latest
# Scan from registry
trivy image nginx:latest
# Scan with detailed output
trivy image --severity HIGH,CRITICAL my-app:latest

Setting Severity Thresholds

Scan with Specific Severity Levels

Terminal window
# Only show critical and high severity issues
trivy image --severity CRITICAL,HIGH my-app:latest
# Exit with error code if vulnerabilities found
trivy image --severity HIGH,CRITICAL --exit-code 1 my-app:latest

Output Formats

Terminal window
# JSON output for parsing
trivy image --format json my-app:latest
# SARIF format for GitHub integration
trivy image --format sarif my-app:latest
# Table format (default)
trivy image --format table my-app:latest

CI/CD Integration

GitHub Actions Workflow

.github/workflows/container-scan.yml
name: Container Vulnerability Scan
on:
push:
branches: [main]
paths:
- 'Dockerfile'
- 'src/**'
pull_request:
branches: [main]
jobs:
trivy-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build Docker image
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile
push: false
load: true
tags: my-app:${{ github.sha }}
- name: Run Trivy vulnerability scan
uses: aquasecurity/trivy-action@master
with:
image-ref: my-app:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
- name: Fail if critical vulnerabilities found
run: |
trivy image --severity CRITICAL my-app:${{ github.sha }} --exit-code 1

GitLab CI Integration

.gitlab-ci.yml
stages:
- build
- scan
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
scan:
stage: scan
image: aquasec/trivy:latest
script:
- trivy image --severity HIGH,CRITICAL --exit-code 1 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
allow_failure: false

Policy Enforcement

Create a Trivy Policy

trivy-policy.yaml
# Define what constitutes a vulnerability violation
severity: HIGH,CRITICAL
# Ignore specific CVEs for known/accepted risks
ignorefile: .trivyignore
# Policy for failing builds
exit-code: 1
# Require sign-off for medium severity
medium-requires-approval: true

Ignoring False Positives

.trivyignore
# Format: CVE-XXXX-XXXXX [optional: expiration date]
# Known false positive or acceptable risk (expires 2026-12-31)
CVE-2024-1234 2026-12-31
# Permanently ignore (use with caution)
CVE-2024-5678

Advanced Scanning Strategies

Scan Filesystems

Terminal window
# Scan local directory
trivy fs .
# Scan with detailed output
trivy fs --severity HIGH,CRITICAL --format json . > fs-scan.json

Scan Configuration Files

Terminal window
# Detect misconfigurations in Dockerfile
trivy config Dockerfile
# Scan Kubernetes manifests
trivy config k8s-manifests/

Generate Software Bill of Materials (SBOM)

Terminal window
# Generate SBOM in CycloneDX format
trivy image --format cyclonedx my-app:latest > sbom.xml
# Generate SBOM in SPDX format
trivy image --format spdx my-app:latest > sbom.spdx

Remediation Workflow

When Vulnerabilities Are Found

  1. Minimal Approach: Update base image
# Before
FROM ubuntu:20.04
# After
FROM ubuntu:22.04
  1. Direct Approach: Update vulnerable dependency
FROM node:18-alpine
# Install with security patches
RUN npm install --no-save my-package@latest
  1. Complete Approach: Rebuild entire image
Terminal window
docker build --no-cache -t my-app:latest .

Real-World Example: Multi-Stage Scanning

.github/workflows/production-scan.yml
name: Production Container Security
on:
schedule:
# Run daily scans
- cron: '0 2 * * *'
workflow_dispatch:
jobs:
scan-all-images:
runs-on: ubuntu-latest
strategy:
matrix:
image:
- my-app:latest
- api-gateway:latest
- worker-service:latest
steps:
- uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ matrix.image }}
format: 'json'
output: 'trivy-${{ matrix.image }}.json'
severity: 'CRITICAL,HIGH,MEDIUM'
- name: Archive results
uses: actions/upload-artifact@v3
with:
name: trivy-reports
path: trivy-*.json
- name: Notify security team
if: failure()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"Critical vulnerabilities found in ${{ matrix.image }}"}' \
${{ secrets.SLACK_WEBHOOK_URL }}

Monitoring and Reporting

Store Results Over Time

Terminal window
# Generate timestamped reports
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
trivy image --format json my-app:latest > reports/scan-$TIMESTAMP.json
#!/bin/bash
# Count vulnerabilities by severity
trivy image --format json my-app:latest | \
jq '[.Results[]?.Vulnerabilities[]?.Severity] | group_by(.) | map({severity: .[0], count: length})'

Best Practices

1. Scan Early and Often

  • Scan during development (local images)
  • Scan in CI/CD pipeline (before merge)
  • Scan in registry (continuous monitoring)
  • Scan in production (runtime detection)

2. Use Minimal Base Images

# Reduce attack surface
FROM alpine:3.18 as base
FROM gcr.io/distroless/base-debian11

3. Regular Dependency Updates

Terminal window
# Update dependencies regularly
npm audit fix --force
python -m pip install --upgrade pip

4. Maintain SBOMs

Generate and store SBOMs for supply chain transparency:

Terminal window
trivy image --format cyclonedx my-app:latest > sbom.json
git add sbom.json
git commit -m "Update SBOM for security tracking"

Integration with Artifact Registry

Push Only Scanned Images

Terminal window
# Only push if scan passes
trivy image --severity CRITICAL,HIGH --exit-code 1 my-app:latest && \
docker push my-registry/my-app:latest

Conclusion

Container vulnerability scanning is non-negotiable in modern DevSecOps.

Trivy makes it simple to detect and prevent vulnerable images from reaching production. Integrate it into your CI/CD pipeline, set enforcement policies, and maintain a culture of continuous security improvement.

Resources

Related Posts

You might also enjoy

Check out some of our other posts on similar topics

Securing CI/CD with IAM Roles

Securing CI/CD with IAM Roles

Why Secure Your CI/CD Pipeline? The Importance of Pipeline Security Hey, want to keep your CI/CD pipeline safe? If you’re working on software, locking down your pipeline is a must. Using

Policy-as-Code Governance with OPA/Rego

Policy-as-Code Governance with OPA/Rego

Why Policy-as-Code Matters The Governance Challenge Managing infrastructure at scale gets complicated fast. As your infrastructure grows, ensuring consistency and compliance becomes incr

7 Reasons Learning the Linux Terminal is Worth It (Even for Beginners)

7 Reasons Learning the Linux Terminal is Worth It (Even for Beginners)

Why Learn the Linux Terminal? The Terminal's Enduring Value Is the Linux terminal still relevant in 2026? You bet it is. Even with all the fancy graphical interfaces and AI assistants ou

Docker Is Eating Your Disk Space (And How PruneMate Fixes It)

Docker Is Eating Your Disk Space (And How PruneMate Fixes It)

The Problem: Docker Is Eating Your Disk Space Symptoms of Docker Disk Space Issues Your Docker host is running out of space. Again. You've been spinning up containers, testing new servic

Structured Logging & Log Aggregation with ELK Stack

Structured Logging & Log Aggregation with ELK Stack

Why Centralized Logging Matters The Logging Crisis When services fail, where do you look first? With distributed systems, logs scatter across servers, containers, and cloud regions. A si

Setting Up GitHub Copilot Agent Skills in Your Repository

Setting Up GitHub Copilot Agent Skills in Your Repository

Why Teach Copilot New Skills? The Power of Specialized Instructions Want Copilot to do more than just autocomplete? If you're ready to teach Copilot some new tricks, Agent Skills are you

6 related posts