Why We Built This

Every week there's a new CVE. And every week, there's that scramble: "Are we affected, and where?"

If your answer involves grepping Slack, pinging teams, or manually checking package files across hundreds of repos — you know the pain. This is what changed for us, how we changed it, and what we're building next. It's running in production today.

What Is an SBOM?

A Software Bill of Materials is a machine-readable inventory of every component in your software — direct and transitive dependencies, versions, licenses, origins. Think ingredients list: if a package gets compromised, you need to know which services contain it.

CycloneDX and SPDX are the standard formats. Generating one is increasingly non-optional (Executive Order 14028, FDA guidance, security questionnaires all ask for it now).

The easy part is generating it. The hard part is what you do with it afterward.

Why SBOMs Matter for Supply Chain Security

Modern apps aren't written — they're assembled. A typical service has a handful of first-party files and hundreds of transitive dependencies. Supply chain attacks target exactly this surface: compromise one popular package and thousands of downstream consumers go down with it.

An SBOM connects the dots: CVEs map to components, components map to your services. Without that link, a CVE is noise. With it, it's an incident you can actually scope and respond to.

How Do You Actually Generate an SBOM?

The tooling is mature and mostly open-source — you don't need to build from scratch:

  • Trivy — Swiss Army knife. Scans filesystems, repos, and container images. Generates SBOMs and flags vulnerabilities in one pass.
  • Syft (Anchore) — purpose-built for container and filesystem scanning. Pairs well with Grype for vulnerability matching.
  • OWASP Dependency-Track/Dependency-Check — Dependency-Check handles code-level reporting; Dependency-Track is an SBOM management platform.
  • Docker Scout — layer-level base image analysis.
  • Language-native plugins — Maven's cyclonedx-maven-plugin, npm's cyclonedx-npm, etc.

Most setups combine a code-level scan (manifests → app dependencies) with an image-level scan (filesystem layers → OS packages). The output (CycloneDX/SPDX JSON) feeds your centralized inventory, which is what makes it queryable and actionable.

Where in the SDLC Should You Pull SBOM Data From?

Pull from multiple points — each catches something the others miss:

SourceCatches
Code repos (SCA)Application-level dependencies
Docker base imagesOS packages inherited before your code runs
Final container imagesActual composition of what ships
CI/CD artifactsBuild-time tools and plugins
IaC / third-party binariesAnything outside package managers

Ideally you're pulling both early (PR-time) and late (full image scan). Code-repo scanning alone misses base image drift; image scanning alone misses the chance to block bad additions before build time.

Why a Centralized SBOM Inventory Is the Real Unlock

The value of an SBOM isn't in any single document — it's in aggregation.

Without a central inventory, a critical CVE means: post in Slack → every team checks individually → some don't respond → some check wrong → compile manually → hours or days pass while attackers move.

With centralization, it becomes: search query → every affected repo, owning team, and a report → in minutes.

This is the single biggest lever for reducing MTTR on supply chain incidents. Detection speed means nothing if correlation speed is slow. The inventory turns "we might be exposed" into "here are the 14 services affected, owned by these 5 teams, here's the report."

How We Solved This: The SBOM Dashboard

We built an internal dashboard to centralize the inventory across our codebase. Here's how:

Dual scan points: We pull SBOM data at PR-time (catches new/changed dependencies before merge, shift-left visibility) and again on a full SAST scan (catches drift, base image changes, transitive updates that slip through). Both feed the same inventory.

Team ownership tagging: Every repository is tagged with its owning team. This single decision makes the dashboard actionable — a vulnerability report is only useful if it comes with "and here's who to page."

Repository dashboards: Each repo gets a view showing vulnerable packages vs. total packages, current component versions, associated CVEs, and license risk. Nothing fancy, but queryable.

CSV and JSON exports: We built JSON export even before we had a use case for it, betting we'd eventually consume it programmatically. That bet paid off fast — JSON output is now feeding our pipelines.

Kill switch: We can block a specific library and version at the pipeline level, even one we don't currently have in inventory. Shifts from detect-then-remediate to detect-then-prevent, which matters when zero-days are actively being exploited.

API from day one: The dashboard has an API because we knew the UI alone wasn't going to be enough. That's what makes pipeline integration and everything downstream (like the MCP work below) possible without ripping everything apart later.

The Problem We Didn't Anticipate

We built this when supply chain attacks were occasional. That's not the case anymore — hundreds of newly-exploited libraries in a single day is the new normal.

Visibility is solved. Triage at scale isn't. Even with perfect inventory, manually checking hundreds of flagged packages a day — exposure, version, team ownership — is a time sink. The dashboard got us halfway there.

Solving the Volume Problem: MCP-Powered Triage

This is the part I'm most excited about. We built an MCP server that sits on top of the SBOM dashboard's API, authenticated via API key, and can be hooked directly into Claude, Cursor, or similar AI coding/agent tools.

The workflow now looks like this: a security engineer gives Claude a natural-language instruction — paste in a blog post, an advisory, or a raw list of CVEs. Claude extracts the library names and versions, queries our SBOM inventory via the MCP server, and returns a structured report: which libraries are vulnerable, what version each affected repo is running, whether that version is actually exploitable per our data, and which team owns the repo.

What used to be an hour of manual cross-referencing per advisory is now a conversation. This has meaningfully improved our MTTR further — not by making detection faster, but by collapsing the triage step that used to sit between "we saw an advisory" and "we know our exposure."

What's Next

Two things are on our roadmap, both aimed at the same goal: separating real risk from noise.

Reachability analysis: Right now, if a vulnerable function exists in a dependency we use, it gets flagged — regardless of whether our code ever actually calls that function. This drives a meaningful false-positive rate and burns reviewer time on non-issues. Reachability analysis will let us say, definitively, "yes, this vulnerable code path is actually invoked by our application," which will sharpen prioritization significantly.

24-hour threat feed automation: Commercial platforms like Wiz, Orca, and Upwind offer continuous scraping and correlation against emerging threats out of the box. If you don't have budget for a paid platform, building a lightweight internal equivalent — auto-scraping new advisories and immediately cross-referencing against your SBOM inventory — closes a real gap between "advisory published" and "you know your exposure," without waiting for a human to even ask the question.

Auto-patching images and code fixes: This is the natural next step beyond detection: closing the loop by actually patching vulnerable base images and raising automated code-level fixes (dependency bumps, PRs) rather than just reporting the problem and handing it off. But this is also the hardest part to get right, because it sits directly at the tension point between security and engineering velocity. Auto-patching done carelessly can break builds, introduce regressions, or flood engineering teams with low-value PRs — which erodes trust in the tooling fast and defeats the purpose. So we're being deliberate about how we architect this: it needs to fit into engineering's existing workflow rather than bolt onto it, it needs confidence scoring before anything gets auto-merged, and it needs an easy opt-out/override path for teams. The goal is to reduce security toil without ever becoming the reason a team's sprint slipped — security and engineering agility have to be designed together, not traded off against each other.

We'll share what we learn as these land.

Takeaway

An SBOM you can't query in an incident is just documentation. The value isn't in generating the artifact — every scanner does that now. The real unlock is centralizing it, tagging ownership, and making it queryable in minutes. Fast enough to keep up with how fast attackers move.

We're not done building. Reachability analysis and threat-feed automation are real force multipliers. But even the current setup — inventory, team tagging, kill switch, and AI-assisted triage — has fundamentally changed our speed from "advisory drops" to "we know exactly where we stand."

If you're starting out: build the inventory first. Everything else compounds from there.