SBOM
Eine SBOM sollte den Build beschreiben, der ausgeliefert wurde
Eine SBOM zur Build-Zeit wird aufgezeichnet, während der Build läuft, aus dem Datenverkehr, der tatsächlich hineinkam. Die meisten SBOM-Generatoren rekonstruieren die Liste dagegen nachträglich aus dem Lockfile oder dem Ergebnis und übersehen so die versteckten Abhängigkeiten, die ein Build selbst lädt. Hier erfahren Sie, warum das so ist und was die Aufzeichnung des Builds ändert.
Aktualisiert am
Build-SBOM, Source-SBOM, Analyzed-SBOM
Der CISA-Leitfaden zu SBOM-Typen ordnet SBOMs danach, wann und wie sie entstehen. Drei davon decken fast jeden gängigen SBOM-Generator ab:
| Typ | Wie sie entsteht | Was sie übersehen kann |
|---|---|---|
| Source | Aus Quelldateien, Manifesten und Lockfiles, meist durch ein SCA-Tool | Laufzeit-, Plugin- oder Plattformkomponenten; alles, was nicht in den Dateien deklariert ist |
| Build | Als Teil des Builds, der das veröffentlichungsfähige Artefakt erzeugt | Alles, was die Build-Umgebung nicht sehen kann, weshalb die Vollständigkeit angegeben werden sollte |
| Analyzed | Nach dem Build, durch Analyse einer ausführbaren Datei, eines Pakets oder eines Container-Images | Komponenten, die das Tool nicht erkennt; die Ergebnisse hängen von Heuristiken ab |
CISA nennt zwei Vorteile einer Build-SBOM: mehr Sicherheit, dass die SBOM das Artefakt korrekt abbildet, wegen der
Informationen, die während des Builds und des CI/CD-Prozesses verfügbar sind, und mehr Vertrauen, weil derselbe Build-Workflow
sowohl die SBOM als auch das Artefakt signieren kann. Als Nachteil nennt CISA, dass Sie möglicherweise den Build-Prozess ändern müssen, um
eine zu erzeugen. Bei CRACI ist diese Änderung eine Zeile, runs-on: craci, und die Aufzeichnung kommt mit dem
Runner.
Einen Ordner scannen oder einen Build aufzeichnen
Die meisten SBOM-Generatoren sind Scanner. Sie richten einen auf einen Quellbaum oder ein Container-Image, und er ermittelt, was seiner Ansicht nach eingeflossen ist, indem er Manifeste, Lockfiles, installierte Pakete oder Binärdateien liest. Das ist nützlich, und bei Software, die Sie nicht selbst gebaut haben, oft die einzige Option.
Die Schwäche: Ein Scanner sieht nur, was ihm vorliegt. Wurde kein Lockfile committet, wurden die Abhängigkeiten vor dem Scan nicht installiert oder wird das Produkt als kompilierte Binärdatei ausgeliefert, hat der Scanner weniger in der Hand als der Build. Ein Scan, der gar keine Komponenten findet, erzeugt trotzdem ein gültiges SBOM-Dokument, und genau das wird vielen zum Verhängnis.
CRACI geht anders vor. Es erzeugt die SBOM in seinem eigenen CI-Runner, sodass das ausgelieferte Artefakt auch das beschriebene Artefakt ist. Es ist kein Scan, der irgendwo daneben lief.
SBOM basics: SPDX, CycloneDX and OpenVEX
Was eine SBOM festhält, wie sich die Formate SPDX und CycloneDX in der Praxis unterscheiden und was OpenVEX zur Frage beiträgt, ob eine Schwachstelle ein Produkt tatsächlich betrifft.
Petteri Pulkkinen und Erika Marttinen bei Kubernetes Community Days Helsinki 2026, 16:50 bis 22:05 aus SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains.
Wovon ein Scan abhängt
Syft, Trivy, cdxgen, das Microsoft SBOM Tool, der Export des Abhängigkeitsgraphen von GitHub und die Socket CLI ermitteln eine SBOM alle aus dem, was sie lesen können. Die folgenden Muster ergeben sich aus der dokumentierten Arbeitsweise dieser Tools.
Tools sind sich uneins, was als Komponente zählt
Jeder Generator entscheidet selbst, was als Komponente zählt und welchen Dateien er vertraut, sodass derselbe gepinnte Commit jedem von ihnen eine andere Liste liefert.
Ein Teil davon liegt an der Benennung. Tools identifizieren dieselbe GitHub Action unter verschiedenen Package-URL-Typen, sodass sie dasselbe auflisten können und trotzdem nicht übereinstimmen. Auch das gehört zum Problem: Eine SBOM, die für eine Komponente eine andere Kennung nutzt, lässt sich schwerer mit Schwachstellendaten abgleichen.
Ob Sie zuerst installiert haben, kann mehr ausmachen als das Tool
Express 5.2.1 committet kein Lockfile. Bei einem frischen Checkout hat ein
Generator, der Abhängigkeiten aus Lockfiles oder einem installierten Baum auflöst,
weder das eine noch das andere vor sich, sodass keine der in
package.json deklarierten npm-Abhängigkeiten das Dokument erreicht. Er kann trotzdem eine Liste liefern,
bestehend aus dem, was er sonst erkennt, etwa GitHub Actions und den
Workflow-Dateien, die sie referenzieren. Keines der Tools ist hier defekt.
Bei einer installierten Kopie desselben Repositorys ändert ein einziges Syft-Flag die Antwort erneut. Dasselbe Tool, derselbe Baum, dieselbe Version. Konstruktionsbedingt meldet ein Syft-Verzeichnisscan, was ein Projekt deklariert, und der Cataloger, der installierte Pakete liest, gehört für Verzeichnisse nicht zum Standardsatz.
Manche Software hat kein Manifest, das sich lesen ließe
Das Repository anthropics/claude-code in v2.1.259 hat keinerlei Abhängigkeitsmanifest:
kein package.json, kein Lockfile oder
Vergleichbares. Was jeder Generator dafür zurückgibt, setzt sich aus anderen
Dateitypen zusammen, sodass die Antwort mehr über das Tool als über das Projekt sagt.
Das veröffentlichte npm-Paket ist kaum anders. @anthropic-ai/claude-code deklariert null Laufzeitabhängigkeiten und
acht plattformspezifische Pakete, die eine vorkompilierte Binärdatei kapseln.
@openai/codex 0.149.1 ist genauso aufgebaut. Was auf dem
Rechner des Entwicklers läuft, ist eine kompilierte Binärdatei, in die kein Manifest-Leser
hineinsehen kann. Das ist kein Fehler eines einzelnen Tools. Es ist ein Vertriebsmodell, das
nachträgliches Scannen nicht beschreiben kann.
Versionen und Lieferanten
Wo zwei Tools dasselbe Paket finden, sind sie sich nicht immer über dessen Version einig. Das eine pinnt eine GitHub Action vielleicht auf einen Commit-SHA, während das andere ein Release-Tag meldet. Eine Schwachstellensuche mit der falschen Version liefert selbstsicher eine falsche Antwort.
Das Lieferantenfeld, eines der NTIA-Mindestelemente, bleibt oft leer, weil die meisten Generatoren keine Quelle dafür haben.
Versteckte Abhängigkeiten: was kein Scan sehen kann
Jedes der oben genannten Tools geht vom Lockfile oder vom Build-Ergebnis aus und leitet daraus ab, was eingeflossen ist. Ein Build lädt mehr als das. Diese versteckten Abhängigkeiten stehen in keinem Lockfile, ein Scan kann sie also nicht finden:
-
Install-Hooks. npm-Skripte wie
preinstallundpostinstalllaufen während der Installation und können weiteren Code herunterladen. So lief der Shai-Hulud-Wurm. - Build-Skripte. Unter anderem Rust-Build-Skripte laden zur Build-Zeit herunter, was sie brauchen.
- Basis-Images. Ein Container-Build zieht ein Basis-Image und dessen Betriebssystem-Schichten, die kein Sprach-Lockfile auflistet.
- Caches und Build-Tools. Aus CI-Caches wiederhergestellte Pakete und von Setup-Schritten installierte Tools kommen ebenfalls am Lockfile vorbei.
Das Ergebnis nachträglich zu scannen schließt die Lücke nicht. Bei einer fertigen Binärdatei, besonders bei kompiliertem Code wie Rust, muss der Scanner raten, was eingeflossen ist.
Zwei Builds, zwei SBOMs
Es gibt einen zweiten Grund, warum ein Scan den Build nicht ersetzen kann: Die meisten Builds sind nicht reproduzierbar. Bauen Sie denselben Commit zweimal direkt hintereinander, gibt es keine Garantie, dass Sie dieselben Pakete erhalten. Paketmanager lösen auf und installieren in der Reihenfolge, in der Antworten eintreffen, was vor allem dann zählt, wenn es kein Lockfile gibt, wie bei vielen Python-Projekten, und Build-Schritte können eigenen Zufall enthalten. Byte-genau reproduzierbare Builds sind möglich, mit Tools wie Nix, aber selten.
Eine SBOM, die später, auf einem anderen Rechner oder aus einem anderen Build erzeugt wird, beschreibt also einen Build, der vielleicht nie ausgeliefert wurde. Nur die SBOM, die während des CI-Builds aufgezeichnet wurde, der ein Release erzeugt hat, belegt, was in Produktion ist.
Was die Aufzeichnung des Builds ändert
CRACI sieht den Datenverkehr, Scanner nicht. Es führt Ihre GitHub-Actions-Jobs auf seinen eigenen Runnern aus und sieht den Netzwerkverkehr, der in jeden Build hineinkommt. Deshalb listet die SBOM auf, was der Job tatsächlich geladen hat, einschließlich transitiver und versteckter Abhängigkeiten, statt dessen, was laut Manifest nötig sein sollte.
Bei Caches wird die Aufzeichnung zur Build-Zeit schwierig. Ein aus einem Cache wiederhergestelltes Paket berührt nie eine Paket-Registry, ein Proxy allein würde es also übersehen. CRACI führt die Abhängigkeitsnachweise mit dem Cache mit, sodass aus einem Cache wiederhergestellte Pakete in der SBOM des Jobs bleiben, der sie wiederhergestellt hat. Siehe was der GitHub-Actions-Cache verbirgt.
Zu den erkannten Ökosystemen gehören npm, PyPI, RubyGems, Cargo, Go, Nix, OCI, apt, apk und Git-Quellen sowie Download-Presets für Yocto und OpenEmbedded. npm- und PyPI-Mirrors von JFrog Artifactory funktionieren. Deklarierte Lizenz-Metadaten sind im Export enthalten. SBOMs werden als CycloneDX und SPDX exportiert. Die Seite SBOM-Generierung beschreibt den vollen Funktionsumfang.
Den Datenverkehr zu sehen funktioniert auch in die andere Richtung. Ein Build braucht Pakete aus bekannten Quellen und veröffentlicht sein Ergebnis an bekannten Orten. Die Egress-Richtlinie von CRACI erlaubt nur diese und blockiert jede andere ausgehende Verbindung sofort, sodass Malware scheitert, die Ihre Secrets an den Server eines Angreifers senden will. Weil die Richtlinie erlaubt, was der Build braucht, statt nach bekannten bösartigen Hosts zu suchen, hält sie selbst dann, wenn Sie das erste Ziel eines Angriffs sind, den noch niemand gesehen hat, wie bei Shai-Hulud. Siehe wie eine Egress-Richtlinie Exfiltration stoppt.
Container- und Docker-SBOMs
Bei Container-Images zeigt sich der Unterschied am deutlichsten. Die üblichen Wege zu einer Docker-SBOM analysieren alle das Image:
Syft und Trivy scannen es, docker scout sbom indiziert seinen Inhalt, wenn das Image keine SBOM-Attestierung
trägt, und die SBOM-Attestierung von BuildKit, aktiviert mit --sbom=true, lässt standardmäßig einen Syft-basierten Scanner
über die letzte Image-Stage laufen. Das ältere Plugin docker sbom wurde zugunsten von
docker scout sbom abgekündigt.
Jedes davon liest das fertige Image und sieht daher, was in den Schichten noch erkennbar ist. Es sieht nicht, was der Build unterwegs geladen hat. CRACI zeichnet den Job auf, der das Image baut: Die Images und Pakete, die der Job aus OCI-Registries und Paketquellen zieht, landen in derselben SBOM wie der Rest des Builds. Bei einem Image, das Sie nicht selbst gebaut haben, bleibt das Scannen die praktische Option. Siehe was Docker-Image-SBOMs übersehen.
Vollständigkeit, pro Job ausgewiesen
Eine aufgezeichnete SBOM ist nur so gut wie die Aufzeichnung. Statt jede SBOM als vollständig darzustellen, gibt CRACI die Vollständigkeit für jeden Job und jeden Cache an, in einem von fünf Status:
- Complete. CRACI hat vollständige Job-Nachweise beobachtet, und jeder wiederhergestellte Cache war vollständig.
- Complete with connections. Die Anforderungen wurden erfüllt, aber der Job nutzte eine oder mehrere benutzerdefinierte Netzwerkverbindungen. Es lohnt sich daher zu prüfen, was über sie hereinkam.
- Incomplete. CRACI hat eine Bedingung erkannt, durch die Abhängigkeiten in der SBOM fehlen könnten.
- Unavailable. CRACI konnte die Auswertung der Nachweise nicht abschließen.
- Not recorded. Der Job ist älter als die Vollständigkeitsberichte.
Vollständigkeit ist über Caches hinweg transitiv. Stellt ein Job einen unvollständigen Cache wieder her, ist auch seine SBOM unvollständig, und jeder Cache, den dieser Job erzeugt, trägt den unvollständigen Status weiter. Sie wissen, auf welche SBOMs Sie sich verlassen können und welche einen zweiten Blick brauchen.
The hard parts: hooks, noise and staying current
Drei Probleme, die der Vortrag benennt: Post-Install-Hooks, die Dinge laden, die in keinem Manifest stehen, die wichtigen Abhängigkeiten in einer langen Liste zu finden und die SBOM aktuell zu halten, was bedeutet, sie bei jedem Build im CI zu erzeugen.
Petteri Pulkkinen und Erika Marttinen bei Kubernetes Community Days Helsinki 2026, 25:39 bis 27:22 aus SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains.
Provenienz über die API
Die SBOM ist ein Teil dessen, was CRACI für jeden Job aufzeichnet. Die API liefert SBOMs, Netzwerk-Traces und Provenienz, alles aus demselben Build aufgezeichnet.
Wo ein Scanner weiterhin das richtige Tool ist
Die Aufzeichnung zur Build-Zeit deckt Software ab, die Sie bauen. Für ein Image oder eine Binärdatei von Dritten, die Sie nicht gebaut haben, bleibt ein Scanner die praktische Wahl, und die oben genannten Tools sind leistungsfähig und weit verbreitet. Es geht nicht darum, dass Scanner schlecht sind. Es geht darum, dass die SBOM Ihrer eigenen Releases aus dem Build kommen sollte, der sie erzeugt hat.
Auch eine CRACI-SBOM hat Grenzen. Sie deckt Jobs ab, die auf CRACI-Runnern laufen, also heute GitHub Actions unter Linux; weitere CI-Systeme stehen auf der Roadmap.
Sie vergleichen Tools? Siehe SBOM-Tools im Vergleich, oder sehen Sie, wie SBOMs zur Build-Zeit zur CRA-Compliance-Arbeit passen. Syft, Trivy und cdxgen im direkten Vergleich finden Sie unter Was Open-Source-SBOM-Generatoren übersehen.
SBOMs zur Build-Zeit: häufig gestellte Fragen
Was ist eine SBOM zur Build-Zeit?
Eine SBOM zur Build-Zeit, von CISA Build-SBOM genannt, entsteht als Teil des Baus des veröffentlichungsfähigen Artefakts. Statt die Komponentenliste nachträglich aus Dateien zu rekonstruieren, beschreibt sie, was der Build selbst verwendet hat. CRACI zeichnet sie aus den Paketen auf, die jeder GitHub-Actions-Job tatsächlich geladen hat.
Was ist der Unterschied zwischen einer Build-SBOM und einer Analyzed-SBOM?
Eine Analyzed-SBOM entsteht nach dem Build durch die Analyse eines Artefakts wie einer ausführbaren Datei oder eines Container-Images, was in der Regel Heuristiken erfordert. Eine Build-SBOM entsteht während des Builds aus Informationen, die dem Build vorliegen. Analyzed-SBOMs funktionieren ohne Zugriff auf den Build und sind daher die richtige Wahl für Software, die Sie nicht gebaut haben.
Wie erzeuge ich eine SBOM für ein Docker-Image?
Scannen Sie ein vorhandenes Image mit einem Generator wie Syft, Trivy oder docker scout sbom. BuildKit kann beim Bauen außerdem eine SBOM-Attestierung anhängen, indem es das finale Image scannt. Um aufzuzeichnen, was der Build eines Images geladen hat, führen Sie den Build auf einem CRACI-Runner aus: Die SBOM des Jobs deckt die geladenen Images und Pakete ab.
Was sind versteckte Abhängigkeiten?
Alles, was ein Build lädt und kein Lockfile auflistet: Code, den npm-Install-Hooks herunterladen, Dateien, die Rust-Build-Skripte zur Build-Zeit herunterladen, und das Basis-Image samt Betriebssystem-Schichten in einem Container-Build. Tools, die das Lockfile lesen oder das Ergebnis scannen, übersehen sie. CRACI zeichnet sie auf, weil es den Datenverkehr sieht, der in den Build hineinkommt.
Warum ergeben zwei Builds desselben Codes unterschiedliche SBOMs?
Weil die meisten Builds nicht reproduzierbar sind. Der Paketmanager löst Pakete in der Reihenfolge auf und installiert sie, in der Antworten eintreffen, besonders ohne Lockfile, und Build-Schritte können Zufall enthalten. Bauen Sie denselben Commit zweimal direkt hintereinander, kann der zweite Build andere Pakete enthalten. Nur die SBOM, die während des Builds aufgezeichnet wurde, der ein Release erzeugt hat, belegt, was dieses Release enthält.
Ist eine SBOM zur Build-Zeit immer vollständig?
Nicht automatisch. Eine Aufzeichnung ist nur so gut wie das, was sie beobachten kann, deshalb gibt CRACI die Vollständigkeit für jeden Job und jeden Cache an: Complete, Complete with connections, Incomplete, Unavailable oder Not recorded. Sie wissen, auf welche SBOMs Sie sich verlassen können und welche einen zweiten Blick brauchen.
Ersetzt eine SBOM zur Build-Zeit SBOM-Scanner?
Für Software, die Sie bauen, ja: Die SBOM Ihrer Releases sollte aus den Builds kommen, die sie erzeugt haben. Für Images und Binärdateien von Dritten, die Sie nicht gebaut haben, bleibt ein Scanner die praktische Wahl. SBOM-Tools im Vergleich zeigt die Optionen.
Welchen SBOM-Generator nutzt CRACI?
Keinen. CRACI scannt keine Dateien. Ein paketbewusster Proxy auf seinen Runnern zeichnet die Pakete auf, die jeder Job aus npm, PyPI, RubyGems, Cargo, Go, Nix, OCI, apt, apk und Git-Quellen sowie über Download-Presets für Yocto und OpenEmbedded lädt, und exportiert das Ergebnis als CycloneDX oder SPDX.
Vergleichen Sie eine SBOM aus Ihrem eigenen Build
Buchen Sie eine Demo und lassen Sie einen Ihrer Workflows auf CRACI laufen. Stellen Sie seine SBOM neben die Ihres aktuellen Tools und sehen Sie die Unterschiede.
Demo buchen