⏱ ~15 min · 📍 Module 4 of 7
This workshop module covers container security scanning to identify vulnerabilities in container images and configurations.
Containers are now one of the most common ways to deploy applications. They are also attractive targets for attackers who can use them to access underlying infrastructure, steal secrets (including cloud credentials), or execute arbitrary code.
Container security scanning analyzes images and container configurations to identify security vulnerabilities, misconfigurations, and compliance issues before releasing them.
- Image Vulnerabilities - Outdated or vulnerable dependencies, both in the base image and in the application dependencies.
- Supply Chain - Untrusted base images. Trojanized or typo-squatted images pulled from public registries.
- Secrets in Images - Hardcoded credentials or keys.
- Root User - Running containers as root
- Excessive Privileges - Unnecessary capabilities can allow container escape.
- Exposed Ports - Unintended network exposure
- Missing Security Controls - No health checks or resource limits
- Weak Network Segmentation - Overly permissive ingress rules allow lateral movement
- Dangerous Volumes - Mounting host volumes can expose sensitive data or allow privilege escalation.
| Tool | What it does | Notes |
|---|---|---|
| Trivy | Vulnerability, misconfiguration and secret scanner for containers | Also scans filesystems, IaC and repos; this module focuses on containers |
| Grype | Fast vulnerability scanner for container images and filesystems | By Anchore; uses multiple vuln DBs and generates SBOM automatically |
By the end of this module, you will:
- Understand container security risks
- Learn to scan images for vulnerabilities
- Understand supply chain security for containers
- Identify Dockerfile security best practices
Tip
A clean scan can take more than one fix. Bumping the base image clears OS-package and language-runtime CVEs, but transitive dependencies bundled inside the new image (e.g., libraries shipped with the global package manager) may still surface as HIGH findings. Expect to fix in layers — re-run the scanner between each change to see what's left.
- Use minimal, trusted base images and rebuild them regularly.
- Patch all High/Critical CVEs before shipping; fail the build if any remain.
- Note: You can also ignore them if you verified the vulnerability is not exploitable.
- Run containers as a non-root user with only the capabilities they truly need.
- Remove build tools & secrets via multi-stage builds to shrink the attack surface.
- Sign images and verify signatures at pull/admission time to ensure provenance.
- Enable runtime protection (seccomp/AppArmor profiles, resource limits, live detection).
- Implement health and readiness checks
- NetRise Releases Supply Chain Visibility & Risk Study, Edition 2: Containers, Revealing Signicant Visibility and Risk Challenges within Common Containers: Research finds containers have over 600 vulnerabilities a piece on average.
- Top 10 Container Security Issues
- Docker Engine security
- slimtoolkit/slim: Tool to reduce the size of container images (making them more secure).
The container bait is the base image in
code/Dockerfile— it ships with an EOL alpine that has unpatched HIGHs. The CI failure is intentional.
Trivy — alpine OS-layer HIGHs (musl, etc.)
What Trivy flagged: an alpine 3.19.4 base ships musl / musl-utils HIGHs (e.g. CVE-2025-26519, CVE-2026-40200) and EOL warnings.
Reading the output: Trivy prints a clean table (Library / Vulnerability / Severity / Status / Installed Version / Fixed Version / Title). This is the gold-standard output across the workshop.
⚠️ Don't just bump alpine minor:node:20-alpine3.19→node:20-alpine3.21actually increases the finding count (alpine 3.21 still ships an unpatched openssl). Jump to a current node-major instead.
⚠️ "Fixed Version" is per-CVE, not per-package: bumping to the version Trivy lists in that column only closes the CVE you happened to look at. Pick the latest stable image tag.
Fix — bump the base image:
-FROM node:20-alpine3.19
+FROM node:25-alpineGrype — same root cause, terser output
What Grype reports: the Summarize findings step parses the SARIF and prints each CVE as ruleId | message | path:line to the job log — plus a helpful warning: 188 packages from EOL distro "alpine 3.19.4". The full SARIF is also uploaded to the GitHub Code Scanning tab if your fork has GHAS enabled.
Same root cause as Trivy: EOL alpine base.
Fix — identical to the Trivy fix above.