Mind the Gap: je SBOM-tool bepaalt wat je SBOM zegt, niet alleen je software
Vanaf december 2027 is een Software Bill of Materials (SBOM) onder de Cyber Resilience Act verplicht. De gangbare aanname is dat een SBOM een objectieve inventaris is: dezelfde software levert dezelfde lijst op. Een nieuwe empirische studie van Prado, Zendra, Boinot en Barais (Inria/IRISA DiverSe en ANSSI, geaccepteerd voor SCORED 2026, Praag) laat zien dat die aanname niet houdbaar is. Dat ligt niet aan slechte tools maar aan de standaard, die op cruciale punten niets voorschrijft.
Wat is onderzocht
De auteurs evalueren drie veelgebruikte open-source SBOM-generators, Syft, Trivy en cdxgen, de tools die in vrijwel elke CRA-handleiding als standaardkeuze worden genoemd, op meer dan 3.000 JavaScript- en Rust-projecten, met een ground truth afgeleid uit dependency-lockfiles.
Een precisie over de dataset-omvang: de primaire PDF is hier intern niet eenduidig: de introductie noemt 2.050 JavaScript- en 1.276 Rust-projecten "built from GitHub, archived via Software Heritage", terwijl de methodologie-sectie spreekt over 2.105 JavaScript-projecten en 1.361 Rust-projecten "collected". Beide staan in dezelfde paper en beide vallen onder het abstract-bereik van "more than 3,000". Een van de twee paren is de subset na het uitsluiten van projecten zonder lockfile; de paper specificeert die relatie niet expliciet. Dit citaat illustreert meteen waarom deze studie ertoe doet voor afnemers: zelfs een academische paper over SBOM-standaarden heeft moeite om hetzelfde fenomeen op twee plekken identiek te rapporteren.
Dat tools uiteenlopen was al bekend uit eerder onderzoek. Deze studie onderzoekt waarom. Een normalisatiepipeline classificeert elke afwijking als representatieverschil (dezelfde dependency, anders gecodeerd), als ontwerpkeuze (bewust toolgedrag) of als toolfout. Met die taxonomie wordt voor het eerst zichtbaar welk deel van de divergentie ruis is en welk deel structuur.
De kernbevinding: systematisch, niet accidenteel
De tools divergeren op dependency-dekking en op volledigheid van de SBOM. Het merendeel van die verschillen is systematisch: ze komen voort uit verschillende aannames over scope, naamgeving, herkomst en representatie van dependencies. Een kleiner deel komt door inconsistente ondersteuning van velden die de specificaties wel definiëren.
De coverage-spreiding over de drie tools is opvallend, geverifieerd uit de paper:
| Tool | JavaScript-coverage | Rust-coverage |
|---|---|---|
| cdxgen | 98,72%, 99,91% | 99,34%, 100% |
| Trivy | 43,78% | 83,85% |
| Syft | 32,71% | 100% |
cdxgen presteert in beide ecosystemen uitstekend. Maar Syft en Trivy dekken slechts 32,71% respectievelijk 43,78% van de JavaScript-dependencies, en halen op Rust wel de 100% (Syft) en 83,85% (Trivy). Een tool die ruim twee derde van je JavaScript-dependencies mist, is geen marginale afwijking: op een SBOM die als grondslag dient voor kwetsbaarheidsscreening, betekent dat een blinde vlek voor de meeste kwetsbaarheden in het transitieve dependency-netwerk.
Concreet betekent dit bijvoorbeeld de vraag of devDependencies in de SBOM horen. De ene tool neemt ze mee en de andere niet, en beide keuzes zijn te verdedigen. Ook aliassen en peer-dependency-suffixen worden verschillend afgehandeld, waardoor hetzelfde pakket onder verschillende identiteiten verschijnt. Wie purl-matching tegen een vulnerability-database doet, weet dat een andere naam in de praktijk een gemiste CVE is.
Operationalisatie van de divergentie, zoals de paper die documenteert:
Scope-divergentie (devDependencies). Syft en Trivy sluiten devDependencies uit van hun SBOM, maar niet consequent: de uitsluiting is per packagemanager verschillend toegepast, en in Rust rapporteert Syft devDependencies wél in Cargo.lock als componenten. De auteurs benadrukken dat dit "not a bug in the traditional sense, but a design choice that has never been applied uniformly." Of een devDependency in je SBOM staat, is een functie van de gekozen tool, niet van de specificatie.
Over-reporting ten opzichte van de baseline. cdxgen en Trivy rapporteren ook componenten die buiten de lockfile-baseline vallen, door drie detectiemechanismen: bestandsnaamdetectie (cdxgen detecteert jquery@3.2.1 uit een bestandsnaam, 786 gevallen), vendored code (handmatig gekopieerde libraries), en het verschil tussen transitieve en directe dependencies.
Identifier-representatie. Zelfs wanneer tools dezelfde component rapporteren, verschillen ze in hoe ze die aanduiden: package-aliasing (een react-dom-entries verwijst naar @hot-loader/react-dom@17.0.2), monorepo- en vendor-path-prefixes, en een andere root-topologie (de drie tools hanteren drie structuren voor hetzelfde root-knooppunt).
Operationeel het meest verontrustend is dit detail, uit de paper: projecten zonder lockfile, wat bij libraries gebruikelijk is, leveren bij twee van de drie tools een lege of ernstig onvolledige SBOM op, zonder foutmelding of waarschuwing. Een lege SBOM is syntactisch valide en passeert elke schema-check in de pipeline, maar zegt niets over de software.
De conclusie van de auteurs is scherp: deze verschillen zijn niet te repareren met bugfixes en vragen om duidelijkere standaardisatie. Nu SBOM-generatie een wettelijke plicht wordt, beïnvloedt de toolkeuze zelf de inhoud van de SBOM. Dat maakt de toolkeuze een mogelijke bron van onopgemerkte non-compliance.
De divergentie wordt pas voelbaar als je twee SBOM's met elkaar vergelijkt. Het volgende fragment toont hoe een component-inventaris al op de naamgevings-normalisatie uiteenloopt:
# SBOM-divergentie-demo: twee tools, zelfde lockfile, andere inventaris
lockfile = {"react-dom": "@hot-loader/react-dom@17.0.2", "istanbul": "istanbul@0.4.3"}
tool_a = {"react-dom@17.0.2", "istanbul@0.4.3"} # echte naam (cdxgen-stijl)
tool_b = {"@hot-loader/react-dom@17.0.2"} # alias-geresolveerd (trivy-stijl)
def sbom_coverage(tool, baseline):
return len(tool & baseline) / max(1, len(baseline))
print(f"Tool A: {sbom_coverage(tool_a, set(lockfile.values())):.0%}")
print(f"Tool B: {sbom_coverage(tool_b, set(lockfile.values())):.0%}")
De boodschap is niet de wiskunde maar de uitkomst: beide tools rapporteren dezelfde dependencies op verschillende namen, waardoor de coverage per tool afwijkt van de werkelijkheid.
Waarom dit een specificatieprobleem is
Hier zit de eigenlijke les. De CRA-tekst is bewust minimaal: een gangbaar machineleesbaar formaat dat ten minste de top-level dependencies dekt. CycloneDX en SPDX definiëren hoe je een component beschrijft. Ze definiëren niet welke componenten erin horen. In architectuurtermen is het datamodel gestandaardiseerd en de semantiek van de populatie niet. Elke toolbouwer vult dat gat zelf in, en doet dat redelijk maar verschillend.
De beste beschikbare houvast is BSI TR-03183-2. Die richtlijn eist CycloneDX 1.6+ of SPDX 3.0.1+, meer dan tien velden per component en recursieve dependency-resolutie. De richtlijn is echter expliciet niet-bindend en geeft geen vermoeden van conformiteit, en de geharmoniseerde Europese standaarden zijn er nog niet. De normatieve leegte die de paper blootlegt, bestaat dus vandaag nog.
De urgentie is groter dan 2027 doet vermoeden. De meldplicht uit artikel 14 van de Cyber Resilience Act geldt sinds 11 september 2026, ook voor producten die al op de markt zijn, met een eerste melding binnen 24 uur. Binnen 24 uur vaststellen of je geraakt bent door een actief misbruikte kwetsbaarheid lukt alleen met een betrouwbare componentinventaris. Een SBOM die devDependencies weglaat of aliassen verkeerd benoemt, faalt op het moment dat je hem nodig hebt.
Kritische kanttekeningen
De sterke kant van de studie is de schaal en vooral de oorzaak-taxonomie. Er zijn ook drie beperkingen om mee te wegen.
De lockfile is zelf een keuze. Een lockfile beschrijft wat is geresolved, niet wat is uitgeleverd. Tree-shaking, bundling, platformspecifieke optionele dependencies en Cargo-features maken dat het gedeployde artefact kleiner of anders kan zijn. De studie meet dus trouw aan de lockfile, niet trouw aan het product, terwijl de CRA over dat product gaat.
De ecosystemen zijn beperkt. Er zijn twee ecosystemen onderzocht, beide met relatief volwassen lockfile-mechanismen. Voor Python, C/C++ of container-images is de situatie vermoedelijk slechter, maar dat is extrapolatie.
De resultaten zijn een momentopname. Toolversies veranderen snel. De categorie ontwerpkeuze is duurzaam, de precieze cijfers zijn dat niet.
Bovendien: er is alleen de lockfile-baseline gemeten, en de divergentie-analyse classificeert de afwijkingen, maar of de ontwerpkeuzes werkelijk allemaal binnen de letter van CycloneDX vallen, verdient externe toetsing.
Wat betekent dit voor de Nederlandse publieke sector
De overheid is zelden fabrikant in CRA-zin. Ze is wel afnemer, en onder NIS2/Cyberbeveiligingswet en BIO2 verantwoordelijk voor ketenbeveiliging en leveranciersmanagement. Zo kan bijvoorbeeld het UWV of de Belastingdienst, dat onder BIO2 de leveranciersketen beoordeelt, een vereiste stellen dat een leverancier van een webgebaseerd dienstenplatform een complete, tool-gepinde SBOM levert. Voor die rol volgen uit de paper vier maatregelen.
- Behandel de SBOM als bewijsstuk met lineage. Leg per SBOM de tool, de versie, de scanmodus (source, build of image) en de scope-configuratie vast. Twee SBOM's zijn zonder die metadata niet vergelijkbaar. In TOGAF-termen hoort dit als architectuurprincipe in de Technology Architecture, niet als pipelinedetail. Zonder een vastgelegde toolkeuze en groundtruth is een verplichte "complete SBOM" niet verifieerbaar: de leverancier kan cdxgen draaien (98-100% coverage) of Syft (32% op JavaScript) en in beide gevallen beweren dat de SBOM volledig is. (Voor de basis over wat een SBOM precies is, zie Software Bill of Materials.)
- Neem het in de inkoopvoorwaarden op. Eis niet "een SBOM" maar conformiteit met TR-03183-2, inclusief een expliciete scope-verklaring (dev, test, build en optional wel of niet meegenomen) en transitieve diepgang.
- Pas differentiële generatie toe als kwaliteitspoort. Genereer met twee tools en behandel de diff als signaal. Laat de build falen bij een lege of verdacht kleine SBOM en dwing lockfiles af, ook voor libraries. De kosten zijn triviaal (
O(d)in het aantal dependencies voor genereren,O(1)per lookup na normalisatie), maar de waarde zit in de semantische keuzes diedcomponenten anders labelen. - Normaliseer identiteiten vóór matching. Canonicaliseer purls en los aliassen op voordat de SBOM Dependency-Track of een vergelijkbaar platform ingaat.
Het risico van niets doen is geen boete in 2027. Het risico is schijnzekerheid nu: een dashboard dat groen staat omdat de kwetsbare component nooit in de inventaris is terechtgekomen. De mitigaties hierboven zijn goedkoop. Het gaat om pipeline-configuratie en contracttekst, en er is geen nieuw platform voor nodig.
Hypothesen en toetsing
Hypothese H1: De divergentie tussen SBOM-generators is grotendeels systematisch, het gevolg van open aannames in de specificatie (scope, naming, provenance, representatie) in plaats van implementatiefouten. Falsifieerbaar: H1 is te falsifiëren wanneer een onafhankelijke replicatie aantoont dat de waargenomen discrepanties kunnen worden verklaard en opgelost door specifieke tool-bugs te herstellen, zonder wijziging aan de specificatie. De auteurs leveren gesteund bewijs via de oorzaak-taxonomie, maar of alle ontwerpkeuzes binnen de letter van CycloneDX vallen, verdient externe toetsing; het is speculatief om te stellen dat elke waargenomen divergentie binnen de specificatie valt.
Hypothese H2: De keuze van een laag-dekkende generator belemmert de detectie van kwetsbaarheden in de transitieve afhankelijkheid, waardoor een SBOM een bron van ongedetecteerde non-compliance wordt. Falsifieerbaar: H2 is te falsifiëren wanneer wordt aangetoond dat de ontbrekende 57-67% van JavaScript-dependencies ook zonder SBOM op andere wijze (bijv. via CI-tooling die lockfiles direct scant) worden gevonden. Dat H2 relevant is staat buiten kijf: de 32-44%-coverage betekent een reële blinde vlek, maar de mate waarin de SBOM daadwerkelijk de bottleneck is, versus de scanner zelf, blijft een open vraag.
Counterfactual: geen open specificaties
Tegenfeitelijk beschouwd: stel dat CycloneDX en SPDX canonieke regels definieerden voor dependency scope, naming, provenance en representatie. Dan zou een SBOM gegenereerd met Syft en een gegenereerd met cdxgen gelijk zijn in component-inventaris voor hetzelfde project. De gevolgen daarvan zouden groot zijn: SBOM-comparators en kwetsbaarheidsscanners zouden één waarheid kennen, contracten zouden één grondwaarheid kunnen specificeren, en de toolkeuze zou als compliance-veranderlijke verdwijnen. Elke keuze (wel of niet devDependencies, alias of echte naam, monorepo-prefix wel of niet) is echter bij een generatief pakketbeheersysteem een trade-off tussen volledigheid en bruikbaarheid. De counterfactual is daarom niet "met canonieke regels is alles opgelost", maar "de kosten van open specificaties zijn nu, vooraf en onzichtbaar, verschoven naar de afnemers die tools moeten vergelijken."
Slot
De auteurs pleiten voor canonieke regels over scope, herkomst en representatie van dependencies in toekomstige SBOM-standaarden. Dat is terecht, en de EN 40000-reeks is de logische plek om die regels vast te leggen. Tot die tijd blijft de SBOM een document waarvan de inhoud afhangt van de gebruikte tool. Wie hem als compliance-bewijs wil gebruiken, moet daarom vastleggen met welke tool en welke configuratie hij is gemaakt. Anders rapporteer je straks niet de waarheid, maar de interpretatie van de tool die je toevallig hebt gekozen, en dat is geen feitenstaat, maar schijnzekerheid.
Bron: Prado, Zendra, Boinot & Barais, "Mind the Gap: How SBOM Specification Ambiguities Lead to Divergent Software Bills of Materials. An Empirical Tool Study", arXiv:2609.19920 (17 september 2026), SCORED 2026, Praag. Kernclaims (dataset-omvang, coverage-percentages, drie divergentie-mechanismen, lege-SBOM-vondst, CRA-deadline en art. 14-meldplicht) geverifieerd tegen de primaire PDF en de verordeningstekst. De paper noemt de dataset intern zowel als 2.050/1.276 als 2.105/1.361 projectparen; beide zijn opgenomen zoals de bron ze rapporteert.
AI & Security Intelligence
Wekelijkse nieuwsbrief met AI updates, security alerts en compliance inzichten, direct in uw inbox.
Security & AI Operating Model
Advisory met executiekracht
Van BIO2 en NIS2 tot EU AI Act, embedded in uw operating model, niet als extern project. Maandelijks opzegbaar, met assessments als bewijsvoering.