124% more reported CVEs per day in 2026 than last year.

SBOM generation, recorded during the build

CRACI is an SBOM generation tool that records what each GitHub Actions build actually pulled in, instead of scanning files afterwards. Every SBOM says how complete it is.

In short: run your GitHub Actions jobs on CRACI runners and every job gets an SBOM of the packages it fetched, including transitive dependencies and packages restored from CI caches, exported in CycloneDX or SPDX. Each SBOM carries a completeness state and is monitored for new vulnerabilities after release. Scanning tools such as Syft and Trivy reconstruct an SBOM from files; CRACI records it from the build. Why build-time SBOMs differ.

Recorded During the Build, Not Scanned Afterwards

Most SBOM generators read files after the build and reconstruct what they think went in. CRACI generates the SBOM inside its own CI runner. A package-aware proxy observes each job's traffic to package sources, so the SBOM lists what the job actually pulled in, transitive dependencies included, rather than what a manifest says it should need. No lockfile, no installed tree and no extra scan step are needed for the record to exist.

Recorded during the build, not scanned afterwards A scanner reads a lockfile or manifest after the fact and reconstructs what it thinks went in. CRACI observes the job's traffic to package sources while the build runs, including packages restored from CI caches, so the SBOM lists what the job actually pulled in. A scanner, after the build Lockfile Scanner SBOM Reconstructs what it thinks went in, from the files it can read Nothing tells you what it missed CRACI, during the build Job fetches Proxy records Job SBOM Lists what the job actually pulled in, including packages restored from CI caches Completeness stated for every job

Every Layer of Transitive Dependencies

Most of what a build pulls in is not a direct dependency. It is a dependency of a dependency, several layers down, and some of it never appears in a lockfile at all: prebuilt binaries a build script downloads, packages restored from a cache, operating system packages. CRACI records every package the job fetched, at every depth, so vulnerabilities are matched against the whole tree. In side-by-side comparisons with other SBOM tools, that more complete record has surfaced vulnerabilities the other tools did not report.

Every layer of transitive dependencies A dependency tree three layers deep. The app depends directly on express, pg and a build script. Express pulls in body-parser and router, which pull in raw-body and path-to-regexp; pg pulls in pg-protocol. The build script fetches a prebuilt library during the build, which bundles a native codec that matches a vulnerability advisory. A lockfile scanner sees the packages the lockfile lists; CRACI records every package the job fetched, at every depth, including the ones only the build pulls in. Your app Direct Layer 2 Layer 3 your-app express pg build script body-parser router pg-protocol prebuilt lib raw-body path-to-regexp native-codec advisory match In the lockfile and the build record Only in the build record: fetched while the job ran Matched an advisory, so it is tracked like any other

Packages Restored From CI Caches Stay in the SBOM

Caches are where build-time recording usually breaks: a package restored from a cache never touches a registry, so a proxy alone would miss it. CRACI carries dependency evidence with the cache, so packages restored from a CI cache stay in the SBOM of the job that restored them.

Packages restored from CI caches stay in the SBOM A first job fetches packages from a registry through CRACI's proxy and saves a cache. The dependency evidence travels with the cache, so when a later job restores it, those packages stay in that job's SBOM even though they never touched a registry. First run: cache miss npm registry Job 1 fetches Cache + evidence Packages recorded through the proxy Later run: cache hit Job 2 restores Cache + evidence No registry request, packages still recorded Job 2 SBOM express 5.2.1 (from cache) lodash 4.17.21 (from cache) Cache-restored packages stay in the SBOM

A Completeness State for Every Job

Vulnerability tracking can only match the components your SBOM lists. A package missing from the SBOM is a vulnerability nobody is alerted about. So instead of presenting every SBOM as complete, CRACI states completeness for each job and each cache: Complete, Complete with connections, Incomplete, Unavailable or Not recorded. You know which SBOMs you can rely on and which need a second look.

A completeness state for every job Instead of presenting every SBOM as complete, CRACI states completeness for each job and each cache: Complete, Complete with connections, Incomplete, Unavailable or Not recorded. Workflow run: SBOM completeness Job Completeness build Complete test Complete with connections integration Incomplete docs Not recorded Why it matters Vulnerability tracking can only match listed components. A package missing from the SBOM is a vulnerability nobody is alerted about, so CRACI says when a list is partial.

The Ecosystems and Formats You Ship

CRACI records packages from npm, PyPI, RubyGems, Cargo, Go, Nix, OCI, apt, apk and Git sources, plus Yocto and OpenEmbedded download presets, and treats JFrog Artifactory npm and PyPI mirrors as known sources. Maven and Java support is on the roadmap. SBOMs export in CycloneDX and SPDX, including transitive dependencies, ready to share with customers, partners and auditors.

Ecosystems and formats CRACI records packages from npm, PyPI, RubyGems, Cargo, Go, Nix, OCI, apt, apk and Git sources, plus Yocto and OpenEmbedded download presets, and treats JFrog Artifactory npm and PyPI mirrors as known sources. Maven and Java are on the roadmap. SBOMs export as CycloneDX or SPDX. Recorded today npm PyPI RubyGems Cargo Go Nix OCI apt · apk Git sources, Yocto presets Artifactory npm, PyPI mirrors On the roadmap Maven and Java Export CycloneDX SPDX With transitive dependencies and declared licenses

Declared Licenses on Every Component

Every recorded package carries its declared license into the SBOM. You can see which dependencies are under a commercial or otherwise restrictive license before you ship, and copyleft licenses are caught before they end up in your product.

Declared licenses on every component Every recorded package carries its declared license into the SBOM, so restrictive and copyleft licenses show up before you ship. License policy rules can block a build on a license. Job SBOM: components and licenses Component Declared license express 5.2.1 MIT requests 2.32.3 Apache-2.0 serde 1.0.219 MIT OR Apache example-lib 1.4.0 GPL-3.0 copyleft License policy Build blocked: GPL-3.0 is not allowed Caught before it ends up in your product

Provenance Through the API

The SBOM is one part of what CRACI records for each job. The public REST API returns SBOMs, network traces and provenance, all recorded from the same build.

Provenance data from every build Every job on CRACI records the packages it fetched and its network trace. The public REST API returns the job's SBOMs, network trace and provenance. Build release job on CRACI Recorded packages fetched network trace Provenance build data, via the API Ask the API about any job Job → SBOM, trace, provenance Returned by the API Job Packages CycloneDX SBOM Network trace Recorded on every CRACI job, no extra step

Monitored After Release

An SBOM is how a company knows what is inside the software it ships, and customers and regulators increasingly ask for one: the Cyber Resilience Act requires manufacturers to draw one up for products sold in the EU. CRACI keeps re-evaluating monitored SBOMs as new vulnerabilities are published, aggregates findings across builds and repositories, and supports VEX. The SBOMs you collect from your own vendors are monitored alongside your builds.

Vulnerability tracking after release After a release ships, its SBOM stays monitored. When a new vulnerability is published, CRACI re-evaluates the monitored SBOMs, finds the affected releases, and the security team triages the finding and routes it to the team that owns the fix. The inventory view shows which software versions are deployed to which products. Release shipped SBOM monitored Later New advisory published Re-evaluated automatically Finding: critical, in 2 releases 1. Triage 2. Route to owner 3. Team fixes Policy gates can block a build on findings · VEX supported Inventory: deployed versions Product Version Web app v4.12.0 Mobile API v2.3.1

A recorded SBOM next to a scanned one

Scanners are the right tool for software you did not build. For your own releases, this is what recording the build changes. A scanner reads the lockfile or the output and works out what went in. CRACI sees the traffic coming into the build, so the hidden dependencies that install hooks, build scripts and base images pull in end up in the SBOM too.

How a scanned SBOM and a recorded SBOM are made Left, a scanner: it reads the lockfile after the build, which lists packages A to E, so its SBOM contains A to E. The build also fetched code through an install hook, a build script download and a base image, which are in no lockfile, so the scanned SBOM is missing them. Right, CRACI: it sees the traffic coming into the build, so all eight packages, including the three hidden dependencies, land in the recorded SBOM. Scanner reads files after the build package-lock.json A B C D E the build also fetched install hook download build script download base image layers in no lockfile, so the scan never sees them Scanned SBOM A B C D E missing missing missing CRACI sees the traffic into the build the network build job on CRACI every package that comes in Recorded SBOM A B C D E install hook build script base image hidden ones too
A scanner can only list what the lockfile or the output declares. CRACI sees what actually came into the build, including the hidden dependencies.
Capability CRACI Scanner-based SBOM tool
How the component list is produced Recorded from the build's own package traffic Reconstructed from files after the fact
Needs a lockfile or installed dependencies No Usually one or the other
Packages restored from CI caches Evidence travels with the cache Only if the files are there when it scans
Completeness state per job Five states, per job and per cache
Signed link from artifact to build No signed provenance With a separate signing step
Software you did not build Add the vendor's SBOM instead
CI systems GitHub Actions today; other CI systems on the roadmap Runs in any CI
  • Included
  • Partly
  • Not included
  • On the roadmap

Comparing specific tools? See SBOM tools compared for Syft, Trivy, cdxgen, the Microsoft SBOM Tool, Dependency-Track and more. For the wider picture, see software supply chain security tools compared.

SBOM basics: SPDX, CycloneDX and OpenVEX

What an SBOM records, how the SPDX and CycloneDX formats differ in practice, and what OpenVEX adds about whether a vulnerability actually affects a product.

Petteri Pulkkinen and Erika Marttinen at Kubernetes Community Days Helsinki 2026, 16:50 to 22:05 of SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains.

SBOM generation: frequently asked questions

What is SBOM generation?

SBOM generation is producing a software bill of materials: a machine-readable list of the components and dependencies in a piece of software. It can be done from source files, during the build, or by analyzing a finished artifact such as a container image. CRACI generates the SBOM during the build, from what the build actually fetched.

How does CRACI generate an SBOM?

Your GitHub Actions jobs run on CRACI runners. As each job runs, a package-aware proxy observes its traffic to package sources and records the packages it pulls in, including transitive dependencies and packages restored from CI caches. Each job gets its own SBOM with a completeness state.

Do I have to change my workflows?

You change runs-on to craci. CRACI replaces the runner, not GitHub Actions, so your workflows and their runs stay in GitHub.

Which package ecosystems does CRACI record?

npm, PyPI, RubyGems, Cargo, Go, Nix, OCI, apt, apk and Git sources, plus Yocto and OpenEmbedded download presets. JFrog Artifactory npm and PyPI mirrors are treated as known sources. Maven and Java support is on the roadmap.

Which SBOM formats can I export?

CycloneDX and SPDX, including transitive dependencies and each component's declared license.

What does the completeness state mean?

Complete means CRACI observed complete job evidence and every restored cache was complete. Complete with connections means the job also used custom network connections worth reviewing. Incomplete means a condition could leave dependencies out. Unavailable means the evidence could not be evaluated, and Not recorded means the job predates completeness reporting.

Does CRACI find vulnerabilities in the SBOM?

Yes. CRACI keeps re-evaluating monitored SBOMs as new vulnerabilities are published, aggregates findings across builds and repositories, and supports VEX. Security teams triage what it finds and send it to the teams that own the fix.

Can CRACI generate an SBOM for software I did not build?

No. CRACI records the builds that run on its runners. For software you buy, add the vendor's SBOM and CRACI monitors it alongside your own builds. For a third-party image you did not build, a scanner is the practical choice; see SBOM tools compared.

See the SBOM of your own build

Book a demo, run one of your GitHub Actions workflows on CRACI and see what it actually pulled in

Book a demo