Software Composition Analysis (SCA) funktioniert gut für npm, Maven oder PyPI. Bei C und C++ hinkt sie seit Jahren hinterher. Bibliotheken wurden in den Quellbaum kopiert, aus dem Betriebssystem installiert oder mit eigenen Skripten gebaut, und nichts hielt fest, welche Versionen in einem Produkt landeten.
Conan hat das geändert. Es gibt C- und C++-Projekten einen aufgelösten, versionierten Abhängigkeitsgraphen und damit die Grundlage für eine echte SBOM. Zwischen dem Wissen, welche Bibliotheken Sie nutzen, und einer Warnung, wenn eine davon eine Schwachstelle hat, klafft aber eine Lücke. In den meisten Conan-Pipelines, die ich gesehen habe, ist diese Lücke der fehlende CPE-Bezeichner. Die SBOM existiert, der Schwachstellenscanner läuft, das Dashboard ist grün, und die CVEs in Ihrer OpenSSL- oder libcurl-Version tauchen nie auf.
Dieser Artikel erklärt, warum das passiert und wie Sie es mit einem kleinen, wartbaren Anreicherungsschritt beheben.
Die SBOM aus dem Build-Graphen erzeugen
Für C++ sollte die SBOM aus dem Abhängigkeitsgraphen kommen, den Conan beim Build auflöst. Das ist die maßgebliche Aufzeichnung dessen, was in den Build eingeflossen ist: jede direkte und transitive Abhängigkeit mit ihrer genauen Version.
Binärscans sind kein Ersatz. Sie erkennen Versionsstrings, Datei-Hashes oder Bytemuster in kompiliertem Code, und C++-Release-Builds hebeln das auf mehrere Arten aus:
- Release-Builds sind meist gestrippt, es gibt also keine Symbole, an denen man sich orientieren kann.
- Statisches Linken verschmilzt Bibliothekscode mit Ihrem Binary, und die Komponentengrenzen verschwinden.
- Bibliotheken, die mit Patches oder ungewöhnlichen Compiler-Flags gebaut wurden, sehen nicht mehr wie die Referenz-Binaries aus, die der Scanner kennt.
Binärscans bleiben eine nützliche zweite Ebene für Code, der an Conan vorbeigeht, etwa kopierte Quellen oder Systembibliotheken. Die Grundwahrheit ist aber der Build-Graph.
Zwei Werkzeuge können die SBOM erzeugen:
- cdxgen liest
conan.lock(Conan 1 und 2) oderconanfile.txtund schreibt eine CycloneDX-SBOM. Abhängigkeiten, die nur inconanfile.pydeklariert sind, liest es nicht. Erstellen Sie also mitconan lock createein Lockfile und committen Sie es. - Conan 2 hat eigene experimentelle SBOM-Werkzeuge,
cyclonedx_1_4undcyclonedx_1_6, die Sie aus einem Hook aufrufen. Sie arbeiten ohne Lockfile mit dem vollständigen Abhängigkeitsgraphen, die Funktion ist aber noch als möglicherweise inkompatibel änderbar gekennzeichnet.
Die Lücke: keine CPE
Das erzeugt cdxgen heute für eine Conan-Komponente:
{
"type": "library",
"name": "openssl",
"version": "3.3.2",
"purl": "pkg:conan/[email protected]"
}
Es gibt eine Package URL (PURL), aber keine CPE. Das ist wichtig, denn Schwachstellendatenbanken suchen Komponenten nicht nach Namen. Jede Quelle nutzt ihren eigenen Bezeichner:
| Schwachstellenquelle | Abgleich über | Deckt Conan-Pakete ab? |
|---|---|---|
| NIST National Vulnerability Database (NVD) | CPE | Ja, über CPE. Hier liegen die meisten CVEs für C und C++. |
| OSV | PURL | Teilweise, über das ConanCenter-Ökosystem |
| Sonatype OSS Index | PURL | Teilweise, für Pakete, die es kennt |
| GitHub Advisory Database | PURL | Nein. Das Conan-Ökosystem ist nicht abgedeckt. |
Für die meisten anderen Ökosysteme bringt Ihnen eine PURL eine gute Abdeckung. Bei C++ sind die Schwachstellen in Bibliotheken wie OpenSSL, zlib, libcurl oder libxml2 in der NVD unter CPE-Bezeichnern erfasst, und die PURL-basierten Quellen decken nur einen Teil davon ab. Ohne CPE lässt sich Ihre SBOM nicht gegen die wichtigste Quelle abgleichen.
OWASP Dependency-Track zeigt das deutlich. Es gleicht NVD-Daten mit der CPE in Ihrer SBOM ab. Version 4 hatte eine Option für unscharfen Abgleich, die CPEs aus Komponentennamen zu erraten versuchte. Dependency-Track 5 hat sie gestrichen, eine Komponente ohne CPE bekommt also gar keine NVD-Befunde. Wenn Sie Dependency-Track betreiben, beschreibt unser Leitfaden zur Bereitstellung von Dependency-Track 5 mit Docker Compose die Einrichtung.
Der Fehler ist still. Der Scan läuft durch, es werden keine Schwachstellen gemeldet, und das Dashboard sieht sauber aus. Nicht weil Ihre Abhängigkeiten sicher sind, sondern weil das Werkzeug sie nicht nachschlagen konnte.
Warum sich die CPE nicht automatisch erzeugen lässt
Ein CPE-2.3-Bezeichner für eine Bibliothek sieht so aus:
cpe:2.3:a:<vendor>:<product>:<version>:*:*:*:*:*:*:*
Das a steht für Application. Hersteller- und Produktnamen stammen aus dem CPE-Wörterbuch der NVD, das NIST unabhängig von jeder Paketregistry pflegt. Viele dieser Namen wurden Jahre vor Conan festgelegt und stimmen oft nicht mit dem Namen des Conan-Pakets überein:
| Conan-Paket | NVD-Hersteller | NVD-Produkt |
|---|---|---|
| openssl | openssl | openssl |
| expat | libexpat | expat |
| libcurl | haxx | libcurl |
| libxml2 | xmlsoft | libxml2 |
| libjpeg-turbo | libjpeg-turbo, und d.r.commander für ältere Versionen | libjpeg-turbo |
Keine Regel führt Sie von libcurl zu haxx. Und eine Stichwortsuche im Wörterbuch liefert auch Distributionspakete: Die Suche nach libpng zeigt zuerst die Einträge redhat:libpng von Red Hat, nicht das Upstream-Projekt libpng:libpng. Der einzige verlässliche Weg ist, dass ein Mensch einmal pro Bibliothek das CPE-Wörterbuch der NVD prüft, nachsieht, welchen Hersteller und welches Produkt die aktuellen CVEs verwenden, und das Ergebnis festhält.
Deshalb machen SBOM-Generatoren das auch nicht. Für npm oder Maven funktioniert eine heuristische Zuordnung gut genug. Für C++ würde sie falsche CPEs liefern, und eine falsche CPE ist schlimmer als keine: Sie scheitert genauso still.
Zwei weitere Dinge sollten Sie über CPEs wissen:
- Eine Bibliothek ohne CVE-Historie hat vielleicht noch keine CPE. NIST legt CPE-Einträge meist bei der Analyse von CVEs an. Das ist in Ordnung, denn es gibt nichts abzugleichen. Die Zuordnung muss aber erneut geprüft werden, sobald die erste CVE erscheint.
- Die NVD reichert weniger CVEs an. Seit April 2026 ergänzt NIST CPE-Daten vor allem bei CVEs aus dem Known-Exploited-Vulnerabilities-Katalog der CISA und bei Software, die die US-Bundesverwaltung nutzt; andere CVEs werden als “Not Scheduled” markiert und bekommen womöglich nie CPE-Daten. Der CPE-Abgleich bleibt für C++ unverzichtbar, reicht allein aber nicht mehr aus. Deshalb ergänzen Sie auch PURLs und mehr als eine Schwachstellenquelle.
Die Lösung: gepflegte CPE-Metadaten plus ein Nachbearbeitungsschritt
Der Ansatz hat zwei Teile:
- Halten Sie für jede Drittanbieter-Bibliothek einmal den geprüften CPE-Hersteller und das CPE-Produkt fest.
- Ergänzen Sie nach dem Erzeugen der SBOM jede Komponente um die CPE und, falls der Generator keine eingetragen hat, um eine PURL.
Speichern Sie nur Hersteller und Produkt, nie den vollständigen CPE-String. Der Nachbearbeitungsschritt fügt die Version aus der SBOM hinzu. Wenn Sie von OpenSSL 3.3.2 auf 3.4.1 aktualisieren, muss sich an Ihren CPE-Metadaten nichts ändern, und die CPE kann nicht von der tatsächlich ausgelieferten Version abweichen.
Wo die Metadaten liegen
Wenn Sie eigene Conan-Rezepte pflegen, gehören die Metadaten ins Rezept. Es enthält bereits Name, Homepage und Lizenz der Komponente, und die CPE gehört daneben:
class OpensslConan(ConanFile):
name = "openssl"
homepage = "https://www.openssl.org"
license = "Apache-2.0"
# Verified against the NVD CPE dictionary
cpe_vendor = "openssl"
cpe_product = "openssl"
Conan ignoriert Attribute, die es nicht kennt, der Build bleibt also unberührt. Ein kurzes Skript kann die Werte aus allen Rezepten einsammeln, ohne sie auszuführen:
"""Collect cpe_vendor/cpe_product from Conan recipes without executing them."""
import ast
import json
import pathlib
import sys
def recipe_metadata(path):
tree = ast.parse(path.read_text(encoding="utf-8"))
for node in tree.body:
if isinstance(node, ast.ClassDef):
values = {}
for stmt in node.body:
if isinstance(stmt, ast.Assign) and isinstance(stmt.value, ast.Constant):
for target in stmt.targets:
if isinstance(target, ast.Name):
values[target.id] = stmt.value.value
if "name" in values:
return values
return None
mapping = {}
for recipe in pathlib.Path(sys.argv[1]).rglob("conanfile.py"):
meta = recipe_metadata(recipe)
if meta and meta.get("cpe_vendor") and meta.get("cpe_product"):
mapping[meta["name"]] = {"cpe_vendor": meta["cpe_vendor"], "cpe_product": meta["cpe_product"]}
json.dump(mapping, sys.stdout, indent=2, sort_keys=True)
Wenn Sie Rezepte direkt aus ConanCenter nutzen, können Sie ihnen keine Attribute hinzufügen. Führen Sie stattdessen eine Zuordnungsdatei in einem Repository, die wie Code reviewt wird:
{
"expat": { "cpe_vendor": "libexpat", "cpe_product": "expat" },
"libcurl": { "cpe_vendor": "haxx", "cpe_product": "libcurl" },
"libxml2": { "cpe_vendor": "xmlsoft", "cpe_product": "libxml2" }
}
Wenn Sie ConanCenter über ein privates Remote spiegeln, zum Beispiel in Artifactory, pflegen Sie eine zentrale Zuordnungsdatei für alles, was darüber läuft, damit jedes Projekt davon profitiert. Gemischte Setups funktionieren auch: Führen Sie die Werte aus Ihren eigenen Rezepten mit der Zuordnungsdatei für öffentliche Pakete zusammen.
Der Nachbearbeitungsschritt
Der Anreicherungsschritt läuft direkt nach dem Erzeugen der SBOM und bevor sie irgendwo hochgeladen wird:
"""Add CPE and Conan PURL identifiers to a CycloneDX SBOM."""
import json
import sys
sbom_path, map_path, out_path = sys.argv[1:4]
sbom = json.load(open(sbom_path, encoding="utf-8"))
cpe_map = json.load(open(map_path, encoding="utf-8"))
missing = []
for comp in sbom.get("components", []):
name, version = comp.get("name"), comp.get("version")
if not name or not version:
continue
comp.setdefault("purl", f"pkg:conan/{name}@{version}")
entry = cpe_map.get(name)
if entry:
comp["cpe"] = f"cpe:2.3:a:{entry['cpe_vendor']}:{entry['cpe_product']}:{version}:*:*:*:*:*:*:*"
elif "cpe" not in comp:
missing.append(f"{name}@{version}")
json.dump(sbom, open(out_path, "w", encoding="utf-8"), indent=2)
for item in missing:
print(f"WARNING: no CPE mapping for {item}", file=sys.stderr)
Nach der Anreicherung sieht die Komponente so aus:
{
"type": "library",
"name": "openssl",
"version": "3.3.2",
"purl": "pkg:conan/[email protected]",
"cpe": "cpe:2.3:a:openssl:openssl:3.3.2:*:*:*:*:*:*:*"
}
Validieren Sie das Ergebnis vor dem Hochladen gegen das CycloneDX-Schema, zum Beispiel mit der CycloneDX CLI oder cyclonedx-python-lib.
Zwei praktische Details. Erstens stimmen Conan-Versionen nicht immer mit denen der NVD überein. ConanCenter verwendet für Bibliotheken ohne Releases Versionen wie cci.20230101, und die NVD schreibt Versionen manchmal anders als die Upstream-Tags. Prüfen Sie pro Bibliothek einige CVEs, ob die Versionsformate zusammenpassen, und ergänzen Sie die Zuordnung um eine Versionsüberschreibung, wo nicht. Zweitens: Behandeln Sie jede Warnung als Lücke, die zu schließen ist. Ergänzen Sie die Zuordnung oder halten Sie fest, warum die Bibliothek keine hat.
Die vollständige Pipeline
Zusammengesetzt sieht die Pipeline so aus:
- Conan löst den Abhängigkeitsgraphen auf und holt Pakete über Ihr privates Remote.
- Der Build kompiliert und linkt.
- cdxgen oder der SBOM-Hook von Conan erzeugt die Basis-SBOM.
- Der Nachbearbeitungsschritt ergänzt CPEs und PURLs, warnt bei Komponenten ohne Zuordnung und validiert das Ergebnis.
- Die Binaries und die angereicherte SBOM werden gemeinsam in Ihrem Artefakt-Repository abgelegt.
- Dependency-Track oder eine andere SCA-Plattform übernimmt die SBOM, gleicht sie mit NVD, OSV und weiteren Quellen ab und überwacht sie weiter.
Der letzte Punkt wird leicht unterschätzt. Wenn eine CVE für eine Bibliothek veröffentlicht wird, die Sie vor sechs Monaten ausgeliefert haben, gleicht Dependency-Track sie mit den vorhandenen SBOMs ab und warnt Sie, aber nur, wenn die CPE beim Hochladen der SBOM schon drin war. Genau diesen nachträglichen Abgleich erwartet der EU Cyber Resilience Act: die Komponenten Ihres Produkts identifizieren und sie während des gesamten Unterstützungszeitraums auf Schwachstellen überwachen. Unser CRA-Leitfaden für KMU behandelt diese Pflichten.
Ergänzen Sie außerdem ein Build-Gate. Lassen Sie den Build scheitern, wenn eine Komponente mit kritischer Schwachstelle hinzukommt, warnen Sie bei hoch und berichten Sie den Rest. Entwickler erfahren dann von einer verwundbaren Abhängigkeit im selben Pipeline-Lauf, der sie eingeführt hat, also dann, wenn die Behebung am günstigsten ist. Die kontinuierliche Überwachung fängt ab, was beim Build noch nicht bekannt war. Sie brauchen beides.
Sonderfälle
Interne Bibliotheken, die andere Teams in Ihrer Organisation bauen und als Conan-Pakete veröffentlichen, haben keine NVD-Einträge und sollten keine CPE bekommen. Geben Sie ihnen eine PURL mit einem repository_url-Qualifier, der auf Ihr privates Remote zeigt, damit sie im Inventar und bei Lizenzprüfungen sichtbar bleiben.
Abhängigkeiten außerhalb des Conan-Graphen sind der eigentliche blinde Fleck: kopierter Quellcode, Bibliotheken aus dem Paketmanager der Build-Maschine und alles, was über FetchContent oder ExternalProject von CMake hereinkommt. Sie erreichen die SBOM nie. Verlagern Sie sie wo möglich in Conan-Rezepte. Wo das nicht geht, ergänzen Sie sie im Nachbearbeitungsschritt mit einer von Hand gepflegten CPE in der SBOM und prüfen Sie regelmäßig auf neue.
Für C++-Bibliotheken, die in keiner Registry liegen, gibt es noch keinen guten PURL-Typ; pkg:generic existiert, aber nur wenige Schwachstellenquellen gleichen darüber ab. Die PURL-Community diskutiert einen neuen Typ für nicht paketierte Software, und PURL selbst wurde im Dezember 2025 als ECMA-427 zur internationalen Norm. Bis ein Typ für nicht paketierte Software kommt, bleibt die CPE der verlässlichste Bezeichner für diese Bibliotheken.
Das Programm um die Menschen herum gestalten, die es nutzen
Die Anreicherung repariert die Daten. Ob das SCA-Programm funktioniert, hängt davon ab, ob es in jeder Entwicklungsphase die richtigen Fragen beantwortet:
- Wie helfen wir Entwicklern, sichere Komponenten auszuwählen?
- Wie verhindern wir, dass Entwickler schlechte Komponenten importieren?
- Wie machen wir es einfach, eine genaue SBOM für bestehende Software zu erstellen?
- Wie kann die QA vor dem Release prüfen, dass es keine neuen SCA-Befunde gibt?
- Wie erfüllen wir die Sicherheitsanforderungen nach dem Release?
Und es muss jedem Team dienen, das davon abhängt, nicht nur dem Security-Team:
| Team | Was es vom SCA-Programm braucht |
|---|---|
| GRC und Recht | Einen Überblick über das Gesamtrisiko durch Drittanbieter-Komponenten im ganzen Unternehmen |
| AppSec | Ein Dashboard zum Überwachen, Triagieren und Nachverfolgen, und Antworten auf Fragen anderer Abteilungen |
| DevOps | Benachrichtigungen über neue Befunde und einen klaren Prozess zum Hinzufügen neuer Repositories |
| Entwickler | Benachrichtigungen über neue Befunde und ein SCA-Werkzeug, mit dem jeder Entwickler sie bewerten und triagieren kann |
| Support | SBOM-Exporte auf Kundenanfrage, dokumentierte Entscheidungen zu Schwachstellen für die Beantwortung von Fragen, und VEX-Dokumente |
| Vertrieb | Eine klare Beschreibung des SCA-Ansatzes für Ausschreibungen, SBOMs mit einer akzeptablen Zahl an Schwachstellen und aktuelle VEX-Dokumente |
Ein Programm, das nur Befunde für das Security-Team erzeugt, bleibt stecken. Eines, das dem Support ein VEX-Dokument zum Versenden und dem Vertrieb eine Antwort für einen Ausschreibungsfragebogen gibt, wird genutzt.
Die Einführung
Ein realistischer Plan für eine bestehende Codebasis dauert etwa acht Wochen:
- Woche 1 und 2, Bestandsaufnahme. Lassen Sie Ihren SBOM-Generator über den aktuellen Build laufen und prüfen Sie, wie viele Komponenten eine CPE haben. Inventarisieren Sie Ihre Rezepte, prüfen Sie, welche Bibliotheken im CPE-Wörterbuch der NVD stehen, und beginnen Sie mit den riskantesten: Kryptografie, Netzwerk und Parser.
- Woche 3 bis 5, Anreicherung. Ergänzen Sie CPE-Hersteller und CPE-Produkt in jedem Drittanbieter-Rezept oder in der Zuordnungsdatei, geprüft gegen die NVD. Machen Sie CPE-Metadaten zur Review-Pflicht für jedes neue Rezept und dokumentieren Sie interne Komponenten separat.
- Woche 6 und 7, Nachbearbeitung bauen. Fügen Sie sie nach der SBOM-Erzeugung in die Pipeline ein, validieren Sie die Ausgabe gegen das CycloneDX-Schema und testen Sie durchgängig: Laden Sie eine angereicherte SBOM hoch und prüfen Sie, dass bekannte CVEs erscheinen.
- Woche 8, Überwachung aktivieren. Übernehmen Sie die angereicherten SBOMs in Ihre SCA-Plattform, richten Sie Warnungen für kritische und hohe Schwachstellen ein, ergänzen Sie das Build-Gate und übergeben Sie den Prozess an die Teams, die ihn betreiben werden.
Das Wichtigste in Kürze
- Erzeugen Sie C++-SBOMs aus dem Abhängigkeitsgraphen von Conan und behandeln Sie Binärscans als zweite Ebene.
- SBOM-Generatoren fügen bestenfalls eine
pkg:conan-PURL hinzu. CPEs fügen sie nicht hinzu, und bei C++ ist die CPE die Verbindung zur NVD. - Prüfen Sie Hersteller- und Produktnamen der CPE von Hand gegen das NVD-Wörterbuch, einmal pro Bibliothek, und speichern Sie sie ohne Version.
- Ergänzen Sie die CPE in einem Nachbearbeitungsschritt und behandeln Sie jede Komponente ohne Zuordnung als Lücke, die zu schließen ist.
- Verlassen Sie sich nicht allein auf die NVD: Seit 2026 reichert sie weniger CVEs an, kombinieren Sie den CPE-Abgleich also mit PURL-basierten Quellen.
- Behalten Sie im Blick, was an Conan vorbeigeht: kopierten Code, Systembibliotheken und über CMake geholte Abhängigkeiten.
Wenn Sie Unterstützung beim Entwurf oder Review Ihres SCA-Programms möchten, vereinbaren Sie ein kostenloses Gespräch.