HackBlue

Tools · Secrets and dependency scanning · 06 / 06

Grype on stored SBOMs: catch new CVEs in images you already shipped

Generate an SBOM with Syft at release time, then rescan it daily with Grype so vulnerabilities published after the release reach the owning team without rebuilding the image.

10 min read · practice only with authorization

The scan that passed last month

A build-time scan reflects the vulnerability database on build day. A CVE published next week affects the same image, but nobody rescans it unless the image is rebuilt. Storing an SBOM with every release, then scanning those SBOMs on a schedule, answers “which running releases are affected now?”.

Syft for the inventory, Grype for the match

Syft lists packages in an image. Grype matches a package list against its vulnerability database. Keeping the two steps separate means the slow part, reading the image, happens once.

Snippet
syft ghcr.io/hackblue-lab/api:2026.10.2 -o cyclonedx-json=sboms/api-2026.10.2.cdx.json

grype db update
grype sbom:sboms/api-2026.10.2.cdx.json --only-fixed --fail-on high

Grype’s table

Rows list the package, installed version, fixed version, ecosystem, identifier, and severity.

Snippet
NAME      INSTALLED  FIXED-IN  TYPE    VULNERABILITY        SEVERITY
openssl   3.0.14-1   3.0.15-1  deb     CVE-2024-6119        High
setuptools 68.0.0    70.0.0    python  CVE-2024-6345        High
discovered vulnerabilities at or above the severity threshold

Worked case: the nightly job

A scheduled job loops over every SBOM for releases still deployed, as listed by the deploy system, and runs Grype with -o json. A small script groups results by owning team and opens one ticket per team, not one per CVE.

An accepted finding goes into .grype.yaml with the package and a comment, so the nightly report stays quiet until something new appears.

Snippet
for f in sboms/*.cdx.json; do
  grype "sbom:$f" --only-fixed -o json > "reports/$(basename "$f" .cdx.json).json"
done

# .grype.yaml
ignore:
  - vulnerability: CVE-2024-6345
    package:
      name: setuptools
      type: python   # build-time only, not in the runtime layer

Diagram

Build-time scan versus scheduled SBOM rescan

Both are needed; they catch different timing.

Build-time scan

Runs. Once, when the image is built

Database. As of build day

Catches. Known issues before release

SBOM rescan

Runs. Every night for deployed releases

Database. As of today

Catches. CVEs published after release

Check yourself

1. Why rescan an SBOM instead of the image itself?

2. What changed when a release that passed last month now fails?

3. Which Grype option keeps the report to issues with an upgrade available?