Image Scanning & CVE Management

You can write the most pristine, bulletproof code in the world, but if your base image (FROM node:14) has a critical vulnerability in openssl, your entire system is compromised before your application even boots.

Image Scanning is the automated process of inspecting the packages inside a container image—both OS-level utilities and application-level dependencies—and matching them against a database of known vulnerabilities (CVEs).

1. The Supply Chain Threat

Modern software is assembled, not written. Think of your application like a gourmet burger:

  • The Recipe (Your Code): 10%
  • The Buns & Sauce (App Dependencies like NPM, Pip): 40%
  • The Meat & Produce (OS Packages like apt, apk): 50%

If your meat supplier ships beef contaminated with Salmonella, it doesn’t matter how well you cook the burger—your customers will get sick. Similarly, if your python:3.9 base image contains a vulnerable version of glibc, an attacker can exploit it to gain root access to your container, completely bypassing your secure application logic.

War Story: The Log4j Nightmare In late 2021, a zero-day vulnerability in Log4j (a ubiquitous Java logging library) broke the internet. Companies scrambled for weeks, not because their own code was vulnerable, but because Log4j was deeply nested in third-party vendor images and base layers. Engineering teams who lacked proper Image Scanning and SBOM generation spent weeks manually SSH-ing into servers to find the vulnerability. Teams with Trivy integrated into their CI/CD found and patched all vulnerable images within minutes.

To prevent this, a scanner generates a Software Bill of Materials (SBOM)—a granular inventory of every package, library, and binary inside your image—and cross-references it against the National Vulnerability Database (NVD).


2. Interactive: Layer Vulnerability Scanner

Images are built in layers. Vulnerabilities often hide deep within base layers you didn’t explicitly write, compounding as each layer adds more dependencies.

Interact with the scanner below to see how vulnerabilities stack up from the OS layer all the way to your application code.

IMAGE LAYERS (Click to Scan)

App Code (app.py)
Pip Packages (flask, requests)
OS Packages (apt-get install)
Base Image (python:3.6)

SCAN RESULTS

> SYSTEM READY. Select a layer to parse SBOM and query NVD database...

3. How Scanners Actually Work (Under the Hood)

You might wonder how a tool can read dependencies inside a binary blob. Container images are just archives. When a scanner like Trivy runs, it performs the following deeply technical sequence:

  1. Tarball Extraction: The scanner pulls the image manifests and unpacks the layer tarballs (.tar.gz files) directly into memory.
  2. Manifest Parsing: It searches for package manager databases (/var/lib/dpkg/status for Debian, /var/lib/apk/db for Alpine) and language lockfiles (package-lock.json, requirements.txt).
  3. SBOM Generation: It compiles a master list of exact versions (e.g., openssl-1.1.1f-1ubuntu2).
  4. Database Cross-Reference: It hashes these findings against a local, offline cache of vulnerability databases (NVD, GitHub Advisories, Alpine SecDB) to find matches.

4. Tools of the Trade

1. Trivy (by Aqua Security)

The industry standard open-source Trivy scanner. It is incredibly fast because it caches the vulnerability DB locally.

Scan an image:

trivy image python:3.9-alpine

Filter by severity and fail the build:

trivy image --severity CRITICAL,HIGH --exit-code 1 python:3.9

Output as JSON (for parsing into dashboards):

trivy image -f json -o results.json python:3.9

2. Docker Scout

Docker Scout is integrated directly into the Docker CLI (replacing the old docker scan). It leverages the syft engine to generate SBOMs and compares them against Docker’s proprietary security advisories.

# Get a high-level summary
docker scout quickview ubuntu:latest

# See all actionable vulnerabilities
docker scout cves ubuntu:latest

5. Automated CI/CD Integration

Scanning locally is good; scanning automatically is mandatory. You must enforce a policy that blocks a build from ever being pushed to your container registry if it contains unpatched critical vulnerabilities.

Here is a concrete GitHub Actions implementation using Trivy:

name: Security Scan
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v3

      - name: Build Image
        run: docker build -t myapp:$ .

      - name: Run Trivy Scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'myapp:$'
          format: 'table'
          exit-code: '1' # This strictly fails the build!
          ignore-unfixed: true
          vuln-type: 'os,library'
          severity: 'CRITICAL,HIGH'

[!TIP] Ignore Unfixed (ignore-unfixed: true): This is crucial. If an OS vulnerability is disclosed today, the OS vendor (like Canonical or Alpine) might not release a patch for a week. If you don’t ignore unfixed vulnerabilities, your build pipeline will remain permanently broken, preventing you from deploying unrelated application fixes. Only block the build if a remediation is available.

6. Remediation Strategies

When your scanner inevitably lights up with red alerts, follow this decision tree to fix them:

  1. Update the Base Image: Vulnerabilities in node:14 will never be fixed because it is end-of-life. Change your Dockerfile to FROM node:20.
  2. Adopt “Slim” or “Alpine” Variants: Standard ubuntu or node images contain hundreds of utilities (wget, curl, bash) that you don’t need. Switching to node:20-alpine dramatically reduces your attack surface.
  3. Adopt “Distroless” Images: Distroless images contain only your application and its runtime dependencies. They do not even have a shell (/bin/sh or /bin/bash). If an attacker finds a Remote Code Execution (RCE) vulnerability in your app, they can’t pop a shell because the shell binary literally doesn’t exist.
  4. Pin and Update OS Packages: If you must install packages via apt-get, ensure you occasionally rebuild the image with apt-get update && apt-get upgrade -y to pull down security patches.
  5. Rebuild Weekly: CVEs are discovered continuously. An image that passed a scan on Monday might fail on Friday without a single line of code changing. Schedule a cron job in your CI to rebuild and scan images weekly.