devsecops
Docker Image Scanning: Security Pipeline
Intermediate
13 minutes
October 2026
CloudOpsGuide Team
Docker Image Scanning: Security Pipeline
Integrate container image scanning into CI/CD pipelines with Trivy, Grype, and Docker Scout — catch vulnerabilities before deployment.
Table of Contents
- Why Scan Images
- Trivy — Fast and Complete
- Grype — SBOM-Focused
- Docker Scout — Built-In
- CI/CD Integration
- Reducing Image Vulnerabilities
Why Scan Images
Container images layer on each other — your app image inherits every vulnerability in the base image plus whatever your layers add:
nginx:alpinemight have 20 known CVEs- Your
node:20base might have 50 npm installmight pull in vulnerable packages- OS packages (
apt install) add more attack surface
Trivy — Fast and Complete
Basic Scan
# Scan an image
trivy image myapp:latest
# Scan for specific severities only
trivy image myapp:latest --severity HIGH,CRITICAL
# Output as JSON for parsing
trivy image myapp:latest --format json -o trivy-report.json
Scan in CI
# Fail pipeline on HIGH/CRITICAL
trivy image myapp:latest --severity HIGH,CRITICAL --exit-code 1
# Scan and generate HTML report
trivy image myapp:latest --format template --template '@contrib/html.tpl' -o report.html
Scan SBOM
# Generate SBOM first
trivy image --format cyclonedx -o sbom.json myapp:latest
# Or scan an existing SBOM
trivy sbom sbom.json
Grype — SBOM-Focused
# Scan image
grype myapp:latest
# Fail on high severity
grype myapp:latest --fail-on high
# Scan from SBOM
syft myapp:latest -o syft-json > sbom.json
grype sbom:sbom.json
Docker Scout — Built-In
# Scout (built into Docker Desktop/CLI)
docker scout cves myapp:latest
# Compare with base image
docker scout compare --to nginx:alpine myapp:latest
# Get recommendations
docker scout recommendations myapp:latest
CI/CD Integration
Jenkins
stage('Build & Scan') {
steps {
sh 'docker build -t myapp:${BUILD_NUMBER} .'
sh '''
trivy image myapp:${BUILD_NUMBER} \
--severity HIGH,CRITICAL \
--exit-code 1 \
--format json -o trivy-${BUILD_NUMBER}.json
'''
}
post {
always {
archiveArtifacts "trivy-*.json"
}
}
}
GitHub Actions
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Scan with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
severity: CRITICAL,HIGH
exit-code: '1'
format: 'sarif'
output: 'trivy.sarif'
- name: Upload to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy.sarif'
GitLab CI
scan:
image: aquasec/trivy:latest
script:
- trivy image $IMAGE_TAG --severity HIGH,CRITICAL --exit-code 1
Reducing Image Vulnerabilities
1. Minimal Base Images
# Before — full Ubuntu image, hundreds of packages
FROM ubuntu:22.04
RUN apt-get install -y nodejs npm
# After — minimal Alpine or distroless
FROM node:20-alpine
# or even better: FROM gcr.io/distroless/nodejs20
Vulnerability reduction: node:20 (~800 CVEs) → node:20-alpine (~20 CVEs) → distroless (~5 CVEs)
2. Multi-Stage Builds
# Build stage — has dev tools (attack surface not in final image)
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Final stage — only production deps
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]
3. Pin Versions
# Before — unpinned, updates break things
FROM node:latest
RUN npm install express
# After — pinned, reproducible
FROM node:20.18.0-alpine3.20
RUN npm install express@4.21.0
4. Clean Package Cache
# apt-get cache adds ~50MB and stale package lists
RUN apt-get update && apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
# apk --no-cache
RUN apk add --no-cache curl
5. Remove Build Tools After Compiling
# gcc/make are needed for native modules but not at runtime
RUN apk add --no-cache --virtual .build gcc make python3 \
&& npm install \
&& apk del .build
Common Fixes
"Vulnerability found in os package"
# Update the base image — pull latest
docker pull node:20-alpine
docker build --no-cache -t myapp:latest .
"Vulnerability found in npm package"
# Check which package has the CVE
trivy image myapp:latest --severity CRITICAL | grep "npm"
# Update in package.json, rebuild
"Vulnerability found in golang binary"
# Rebuild with updated Go toolchain
docker build --build-arg GO_VERSION=1.23 -t myapp:latest .
Scanning Strategy
PR opened ──► SAST + dep scan (fast, catch code issues)
Merge to main ──► Build + Trivy scan (catch image issues)
Deploy to staging ──► DAST scan (catch runtime issues)
Deploy to prod ──► Runtime monitoring (catch live issues)
Related Articles
Last Updated: October 2026
Author: CloudOpsGuide Team
Difficulty: Intermediate
Estimated Reading Time: 13 minutes