Container Security

Container Image Scanning: Tools and Best Practices

Caliptra TeamDec 1, 20258 min read


Why Scan Container Images?

Container images are essentially a snapshot of your application plus all its dependencies. Those dependencies can contain vulnerabilities — and often do.

The average container image contains:

  • An OS base layer (Debian, Alpine, etc.)

  • System packages

  • Language runtimes (Node, Python, Go, etc.)

  • Application dependencies

  • Your application code


Each layer can introduce vulnerabilities. Container scanning finds them before they reach production.

What Scanners Look For

Container image scanners check for:

  • OS package vulnerabilities — CVEs in apt/apk/yum packages

  • Language dependency vulnerabilities — CVEs in npm, pip, gem packages

  • Misconfigurations — Dockerfile security issues

  • Secrets — Accidentally included credentials

  • Malware — Known malicious files


Tool Comparison

Trivy

Best for: Most teams, especially those wanting a single tool

Trivy is our recommended default. It's fast, comprehensive, and easy to use.

Pros:

  • Scans images, IaC, filesystems, git repos

  • Very fast (caches vulnerability database)

  • Great CI/CD integration

  • Active development, frequent updates

  • Free and open source


Cons:
  • Less enterprise features than commercial tools


Usage:
# Scan an image
trivy image myapp:latest

# Scan with severity filter
trivy image --severity HIGH,CRITICAL myapp:latest

# Output as JSON for CI/CD
trivy image --format json --output results.json myapp:latest

Grype

Best for: Teams wanting Anchore ecosystem integration

Grype is from Anchore and pairs well with their SBOM tool, Syft.

Pros:

  • Fast and accurate

  • SBOM-first approach

  • Good Kubernetes integration

  • Free and open source


Cons:
  • Narrower scope than Trivy (images only)


Usage:
# Scan an image
grype myapp:latest

# Generate SBOM first, then scan
syft myapp:latest -o json > sbom.json
grype sbom:sbom.json

Snyk Container

Best for: Teams wanting developer experience and fix suggestions

Snyk is commercial but has a free tier. It excels at developer experience.

Pros:

  • Great fix suggestions

  • IDE integration

  • Developer-friendly UX

  • Good base image recommendations


Cons:
  • Commercial (free tier has limits)

  • Slower than Trivy/Grype


Clair

Best for: Teams already using Quay registry

Clair was one of the first open source scanners. It's mature but showing its age.

Pros:

  • Mature and battle-tested

  • Good registry integration


Cons:
  • Complex setup

  • Slower development pace

  • Less comprehensive than newer tools


Best Practices

1. Scan Early and Often

Don't wait until deployment. Scan at every stage:

  • Developer workstation — IDE plugins, pre-commit hooks

  • Pull request — Block PRs with critical vulnerabilities

  • Build pipeline — Scan after image build

  • Registry — Continuous scanning of stored images

  • Runtime — Admission controllers block vulnerable images


2. Use Minimal Base Images

Smaller images = fewer vulnerabilities. Consider:

  • Distroless — Google's minimal images (no shell, minimal OS)

  • Alpine — Tiny Linux distribution

  • Scratch — Empty image (for Go binaries, etc.)


# Instead of
FROM ubuntu:22.04

# Use
FROM gcr.io/distroless/static-debian11

3. Set Severity Thresholds

Don't just scan — enforce. Block deployments based on severity:

# In CI/CD
trivy image --exit-code 1 --severity CRITICAL myapp:latest

4. Fix What Matters

Not all vulnerabilities are equal. Prioritize based on:

  • CVSS score — Severity of the vulnerability

  • Exploitability — Is there a known exploit?

  • Fix availability — Can you actually fix it?

  • Context — Is the vulnerable component even used?


5. Keep Base Images Updated

Regularly rebuild images with updated base images:

# GitHub Actions example - weekly rebuild
on:
schedule:
- cron: '0 0 0' # Weekly on Sunday
jobs:
rebuild:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and push
run: |
docker build --pull -t myapp:latest .
docker push myapp:latest

6. Generate and Store SBOMs

A Software Bill of Materials (SBOM) documents all components in your image. Generate one for every image:

# Generate SBOM with Syft
syft myapp:latest -o spdx-json > sbom.json

# Or with Trivy
trivy image --format spdx-json -o sbom.json myapp:latest

CI/CD Integration Example

Here's a complete GitHub Actions workflow:

name: Build and Scan

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build-and-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Build image
run: docker build -t myapp:${{ github.sha }} .

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1'

- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'

Quick Start Checklist

  • Choose a scanner (we recommend Trivy)

  • Add scanning to your CI/CD pipeline

  • Set severity thresholds (block CRITICAL at minimum)

  • Switch to minimal base images

  • Enable automatic base image updates

  • Generate SBOMs for compliance


Need Help?

If you want help implementing container security in your CI/CD pipeline, we can help. We'll set up scanning, configure thresholds, and make sure nothing vulnerable reaches production.

Need Help With Container Security?

Our team can help you implement the practices discussed in this article. Let's talk about your specific needs.

Explore Our Services