beginner ~45 min updated 2026-06-01
Trivy Container Scan
Scan container images for CVEs, misconfigurations, and secrets with Trivy. Compare a vulnerable base image against a patched one, generate an SBOM, and gate a CI build on severity.
Objective
Use Trivy to find vulnerabilities and secrets in a container image, fix them by changing the base image, and fail builds on HIGH or CRITICAL findings. You will also produce a CycloneDX SBOM and scan a Dockerfile for misconfigurations.
Prerequisites
- Docker installed and running
- Trivy installed (
trivy --versionworks) — install withbrew install trivyorcurl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin - Basic Dockerfile knowledge
- Internet access for the first vulnerability DB download (~60 MB)
Architecture
Trivy pulls the target image, unpacks its layers, identifies OS packages and language dependencies, and matches them against its vulnerability database. The same engine also scans for hardcoded secrets and Dockerfile/IaC misconfigurations. Exit codes make it CI-friendly.
+-----------+ pull/unpack +---------------------+
| Image | --------------> | Trivy |
| (registry | | - vuln DB matching |
| or local)| | - secret rules |
+-----------+ | - misconfig checks |
Dockerfile ---------------> | |
+---------+-----------+
|
report (table/json/SBOM) + exit code
Steps
1. Scan a deliberately old image
docker pull python:3.4-alpine
trivy image --severity HIGH,CRITICAL python:3.4-alpine
2. Build an image with a planted secret
mkdir trivy-lab && cd trivy-lab
# Dockerfile
FROM python:3.4-alpine
ENV AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
COPY app.py /app/app.py
USER root
CMD ["python", "/app/app.py"]
echo 'print("hello")' > app.py
docker build -t trivy-lab:vulnerable .
3. Run a full scan: vulnerabilities plus secrets
trivy image --scanners vuln,secret trivy-lab:vulnerable
4. Scan the Dockerfile for misconfigurations
trivy config .
Trivy flags issues such as running as root and missing HEALTHCHECK.
5. Fix the image and rescan
# Dockerfile.fixed
FROM python:3.13-alpine
COPY app.py /app/app.py
RUN adduser -D appuser
USER appuser
CMD ["python", "/app/app.py"]
docker build -f Dockerfile.fixed -t trivy-lab:fixed .
trivy image --severity HIGH,CRITICAL trivy-lab:fixed
6. Gate a build on severity and generate an SBOM
# Non-zero exit code if HIGH/CRITICAL vulns exist -> perfect for CI
trivy image --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed trivy-lab:fixed
echo "Gate exit code: $?"
# CycloneDX SBOM
trivy image --format cyclonedx --output sbom.cdx.json trivy-lab:fixed
python3 -c "import json;d=json.load(open('sbom.cdx.json'));print(len(d['components']),'components')"
Expected output
$ trivy image --severity HIGH,CRITICAL python:3.4-alpine
python:3.4-alpine (alpine 3.9.2)
Total: 35 (HIGH: 27, CRITICAL: 8)
┌────────────┬────────────────┬──────────┬─────────────────┐
│ Library │ Vulnerability │ Severity │ Fixed Version │
├────────────┼────────────────┼──────────┼─────────────────┤
│ musl │ CVE-2019-14697 │ CRITICAL │ 1.1.20-r5 │
│ openssl │ CVE-2019-1543 │ HIGH │ 1.1.1b-r1 │
...
$ trivy image --scanners vuln,secret trivy-lab:vulnerable
...
trivy-lab:vulnerable (secrets)
CRITICAL: AWS (aws-secret-access-key)
ENV AWS_SECRET_ACCESS_KEY=*****
$ trivy image --severity HIGH,CRITICAL trivy-lab:fixed
trivy-lab:fixed (alpine 3.21.x)
Total: 0 (HIGH: 0, CRITICAL: 0)
Gate exit code: 0
Troubleshooting
failed to download vulnerability DB: network/proxy issue or GitHub rate limiting. Retry, or setTRIVY_DB_REPOSITORYto a mirror; behind a proxy exportHTTPS_PROXY.- Scan is very slow the first time: that is the one-time DB download. Subsequent scans use the local cache in
~/.cache/trivy. image not foundfor a locally built image: Trivy defaults to the Docker daemon but can fall back to remote registries. Make sure the tag matchesdocker imagesoutput exactly and Docker is running.- Secret not detected: secrets baked via
ENVare found in image config; ensure you scan the built image, not the Dockerfile, with--scanners secret. trivy config .reports nothing: the Dockerfile must be in the scanned directory and namedDockerfile*. Check you are intrivy-lab/.
Cleanup
docker rmi trivy-lab:vulnerable trivy-lab:fixed python:3.4-alpine python:3.13-alpine
trivy clean --all
cd .. && rm -rf trivy-lab