iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Vulnerability Scanning

Docker image scanning: Trivy, Grype, Snyk, Docker Scout. Catch CVEs in dependencies before they ship.

Docker — image scanning

EXAMPLE
# ===== Why scan =====
# Container images embed Linux distro + your deps + your app.
# Every layer can have CVEs. Scanners check each layer against vulnerability databases.

# ===== Trivy (open-source, popular) =====
# Install:
brew install trivy
# or:
docker run aquasec/trivy image alpine:latest

# Scan an image:
trivy image nginx:1.25-alpine

# Scan a file system (build directory):
trivy fs ./

# Scan a Dockerfile:
trivy config Dockerfile

# Output formats:
trivy image -f json -o report.json nginx:latest
trivy image -f sarif -o report.sarif nginx:latest

# Fail CI on HIGH+ findings:
trivy image --severity HIGH,CRITICAL --exit-code 1 myapp:dev

# ===== Grype (Anchore, also open-source) =====
brew install grype
grype nginx:latest
grype sbom:./sbom.json     # scan from SBOM

# ===== Docker Scout (built in to Docker Desktop) =====
docker scout cves nginx:latest
docker scout recommendations nginx:latest

# ===== Snyk =====
brew install snyk
snyk container test nginx:latest
snyk container monitor nginx:latest

# ===== In CI (GitHub Actions) =====
name: scan
on: [pull_request]
jobs:
  trivy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aquasecurity/trivy-action@master
        with:
          image-ref: myapp:${{ github.sha }}
          severity: 'HIGH,CRITICAL'
          exit-code: '1'
          format: 'sarif'
          output: trivy.sarif
      - uses: github/codeql-action/upload-sarif@v3
        with: { sarif_file: trivy.sarif }

# ===== Reduce attack surface =====
# 1. Smaller base images:  alpine, distroless, scratch (for static binaries)
# 2. Multi-stage build:    leave build tools in builder stage; runtime is minimal
# 3. Pin base by digest:   FROM node:20-alpine@sha256:...
# 4. Update regularly:     monthly base bumps; CI gates on scan results
# 5. Non-root user:        USER node in Dockerfile

# ===== Multi-stage example =====
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER nonroot
CMD ["dist/server.js"]

# Distroless removes shells + package managers; tiny + low CVE surface.

# ===== SBOM (Software Bill of Materials) =====
trivy image --format cyclonedx -o sbom.json nginx:latest
syft nginx:latest -o cyclonedx-json > sbom.json

# Ship the SBOM with each release; auditors love them.

# ===== Patterns =====
# - Scan in CI on every PR
# - Fail on HIGH+ findings; ticket MEDIUM
# - SBOM published with each image
# - Distroless / minimal base in production

# ===== Pitfalls =====
# - Scanning only ON RELEASE -> CVEs ship to prod
# - Ignoring CVEs in 'system' libraries you don't use directly (still a risk)
# - Old vulnerability DB cached -> always update
# - Allowlists without expiry / reviewer -> findings rot

Why it matters

Scan images in CI; fail on HIGH+ findings. Trivy / Grype / Scout / Snyk all work. Pair with minimal base (alpine, distroless), multi-stage builds, non-root user, and SBOM. The CVE story is hygiene, not a one-off audit.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
docker scout cves my-api:1.0
# Trivy is another popular open-source scanner.
Try it Yourself »

Discussion

Loading…