Generating and Managing Docker Image SBOMs with Syft and Grype: Securing Your Container Supply Chain

Do You Really Know What’s Inside Your Docker Image?

Most of us start working with Docker with a simple goal: write a Dockerfile that gets the app running, build the image, and push it to GitHub Container Registry (GHCR), Docker Hub, or AWS ECR. Looking at a Dockerfile starting with FROM node:18-bullseye-slim, the image seems neat and lightweight. However, beyond risks like leaking API keys in image layers, it drags along over 90 Debian packages (such as libssl, libc6, curl) alongside a deeply nested tree of npm libraries that you never manually installed.

In 2021, the Log4j vulnerability (CVE-2021-44228) erupted. The first question a tech lead or SecOps team dropped into the team chat was usually: “Are any of our production images affected by Log4j?”. If you had to SSH into every server and exec into running containers just to run commands searching for .jar files, you were already hours behind the incident.

The Trio: SBOM, Syft, and Grype

What Is an SBOM (Software Bill of Materials)?

An SBOM acts much like the nutrition facts printed on a food label or an itemized parts list when building a PC. In the container world, an SBOM explicitly lists every component: package names, exact versions, authors, associated licenses, and SHA-256 hashes. This inventory encompasses both OS-level packages (such as apt, apk, rpm) and application-level dependencies (npm, pip, maven, Go modules).

Today, the industry has standardized around two primary formats:

  • SPDX (Software Package Data Exchange): An open standard from the Linux Foundation, optimized for copyright compliance and open-source license audits.
  • CycloneDX: An OWASP-driven standard designed specifically for application security risk assessment and supply chain analysis.

The Dynamic Duo from Anchore: Syft and Grype

Instead of writing complex custom layer-parsing scripts, the DevSecOps community turns to Anchore’s open-source duo:

  • Syft: A CLI tool that scans images, filesystems, or code repositories and generates standard SBOM files in just 2 to 4 seconds.
  • Grype: A vulnerability scanner that directly ingests SBOM files produced by Syft. Grype matches that data against continuously updated CVE sources (NVD, GitHub Advisories, Alpine SecDB) to pinpoint vulnerable packages.

Hands-on: Generating and Auditing SBOMs from A to Z

Step 1: Install Syft and Grype

On Linux or macOS, you can install them quickly using their official installation scripts:

# Install Syft
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin

# Install Grype
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin

# Verify versions
syft version
grype version

If you’re on macOS with Homebrew installed, simply run brew install syft grype.

Step 2: Prepare a Sample Docker Image

Let’s create a small Node.js application containing an outdated, intentionally vulnerable dependency to test the workflow:

mkdir sbom-demo && cd sbom-demo
npm init -y
npm install express [email protected]

Create a Dockerfile:

FROM node:18-bullseye-slim
WORKDIR /app
COPY package*.json ./
RUN npm install --omit=dev
COPY . .
CMD ["node", "index.js"]

Build the image locally:

docker build -t my-app:1.0.0 .

Step 3: Extract the SBOM Using Syft

To quickly inspect packages directly in your terminal, simply pass the image name:

syft my-app:1.0.0

The output table displays package names, installed versions, and package types (deb, npm). Next, export a full SBOM in CycloneDX JSON format:

syft my-app:1.0.0 -o cyclonedx-json > sbom-my-app.json

The resulting file often spans several thousand lines and weighs between 300KB and 1MB. The JSON structure includes deeply nested dependency trees. To inspect or search fields like components, hashes, or licensing details, you can quickly paste the contents into toolcraft.app/en/tools/developer/json-formatter to format and collapse tree branches visually.

If your project requires the SPDX standard, change the format flag to spdx-json:

syft my-app:1.0.0 -o spdx-json > sbom-my-app.spdx.json

Step 4: Scan for Vulnerabilities with Grype

The beauty of storing SBOM files is that you don’t need to keep or pull a 500MB image every time you perform a security audit. You only need to feed the lightweight JSON file into Grype:

grype sbom:./sbom-my-app.json

The command completes in under 2 seconds. Grype outputs a detailed vulnerability report:

NAME    INSTALLED  FIXED-IN  TYPE  VULNERABILITY   SEVERITY
lodash  4.17.20    4.17.21   npm   CVE-2021-23337  High
lodash  4.17.20    4.17.21   npm   CVE-2020-28500  Medium

The output clearly indicates that [email protected] carries a High-severity vulnerability (Command Injection via template), and upgrading the package to 4.17.21 resolves the issue.

Step 5: Block Vulnerable Images in GitHub Actions

Don’t wait until after deployment to run manual scans. The best practice is to turn vulnerability checking into a mandatory quality gate within your CI/CD pipeline.

The workflow file below automatically generates an SBOM and fails the pipeline if any vulnerability rated High or above is detected:

name: Docker Security Pipeline

on:
  push:
    branches: [ "main" ]

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

      - name: Build Docker Image
        run: docker build -t my-app:${{ github.sha }} .

      - name: Generate SBOM with Syft
        uses: anchore/sbom-action@v0
        with:
          image: my-app:${{ github.sha }}
          format: cyclonedx-json
          output-file: sbom.json

      - name: Scan Vulnerabilities with Grype
        uses: anchore/scan-action@v4
        with:
          sbom: sbom.json
          fail-build: true
          severity-cutoff: high

If someone accidentally adds a dependency containing a critical or high CVE, the pull request fails immediately at the CI stage, preventing vulnerable code from ever reaching production.

Conclusion

Integrating Syft and Grype into your container build process shifts security management from reactive to proactive. Combined with Docker Content Trust to block malicious images, pairing every commit with an SBOM serves as a transparent birth certificate. When a zero-day vulnerability drops, auditing your entire catalog takes seconds by querying SBOM files rather than frantically digging through live production servers.

Share: