123% mehr gemeldete CVEs pro Tag in 2026 als im Vorjahr.

Abhängigkeiten

Was ist eine transitive Abhängigkeit?

Eine transitive Abhängigkeit ist ein Paket, das Ihre Software nutzt, weil ein anderes Paket es braucht. Sie haben es nie deklariert, aber es steckt in dem, was Sie ausliefern, mit eigenen Schwachstellen und eigener Lizenz. Hier erfahren Sie, wie Sie diese Pakete sehen, beheben und belegen, welche in jedes Release eingeflossen sind.

Aktualisiert am

A vulnerable transitive dependency and its fix path An app declares two direct dependencies, express and hbs. Express brings in body-parser and send, which bring in raw-body and mime-types. Hbs brings in handlebars, which is vulnerable. The path from the app through hbs to handlebars is highlighted: upgrade hbs, or override the handlebars version. your project direct transitive, depth 1 depth 2 my-app express hbs body-parser send handlebars vulnerable, required by hbs raw-body mime-types Fix path: upgrade hbs, or override the handlebars version

Direkte und transitive Abhängigkeiten

Eine direkte Abhängigkeit deklarieren Sie in Ihrem Manifest. Eine transitive Abhängigkeit deklarieren Ihre Abhängigkeiten, und deren Abhängigkeiten wiederum ihre eigenen, so tief der Baum reicht. Der Paketmanager löst bei der Installation den gesamten Baum auf und hält das Ergebnis meist in einem Lockfile fest.

Nehmen Sie eine App, die ein einziges Paket deklariert: express. npm ls --all zeigt, was diese eine Zeile mitbringt:

my-app
└─┬ express            ← direkt: von Ihnen deklariert
  ├─┬ body-parser      ← transitiv, Tiefe 1
  │ └── raw-body       ← transitiv, Tiefe 2
  ├── cookie           ← transitiv, Tiefe 1
  └─┬ send             ← transitiv, Tiefe 1
    └── mime-types     ← transitiv, Tiefe 2

Der echte Baum ist länger. Die meisten Pakete einer typischen Anwendung kommen auf diesem Weg hinein. Das heißt: Den Großteil des Codes, den Sie ausliefern, hat der Paketmanager ausgewählt, nicht Sie.

Direkte Abhängigkeit Transitive Abhängigkeit
Wer sie ausgewählt hat Ihr Team, im Manifest Der Paketmanager, anhand der Manifeste Ihrer Abhängigkeiten
Wo sie aufgeführt ist Manifest und Lockfile Lockfile, falls vorhanden
Wer die Version kontrolliert Sie Der Versionsbereich des übergeordneten Pakets, sofern Sie ihn nicht überschreiben
Wie Sie eine Schwachstelle beheben Aktualisieren Das übergeordnete Paket aktualisieren oder die Version überschreiben

Warum transitive Abhängigkeiten wichtig sind

Sie bergen dieselben Risiken wie direkte Abhängigkeiten, bei weniger Sichtbarkeit und weniger Kontrolle.

  • Schwachstellen. Als Log4Shell, eine Zero-Day-Schwachstelle in log4j, bekannt wurde, fand das Team von Googles Open Source Insights 35.863 Artefakte auf Maven Central, die vom betroffenen log4j-Code abhingen. Rund 7.000 davon hingen direkt von ihm ab. Die Mehrheit zog ihn als transitive Abhängigkeit nach, und viele ließen sich erst beheben, nachdem ein Paket dazwischen selbst einen Fix ausgeliefert hatte.
  • Lieferkettenangriffe. Die xz-utils-Hintertür (CVE-2024-3094) erreichte OpenSSH, ohne dass OpenSSH von xz abhing. Mehrere Linux-Distributionen patchen OpenSSH für die systemd-Benachrichtigung, und libsystemd hängt von liblzma ab, der Bibliothek, die xz bereitstellt.
  • Lizenzen. Jedes transitive Paket hat seine eigene Lizenz. Eine Copyleft-Lizenz drei Ebenen tiefer bindet genauso wie eine, die Sie selbst hinzugefügt haben.
  • Breaking Changes. Ein übergeordnetes Paket, das einen Versionsbereich akzeptiert, lässt bei der nächsten frischen Installation ein neues transitives Release herein, selbst wenn sich in Ihrem Manifest nichts geändert hat.

So listen Sie Ihre transitiven Abhängigkeiten auf

Jeder große Paketmanager kann den aufgelösten Baum ausgeben:

Ökosystem Befehl
npmnpm ls --all
pnpmpnpm list --depth Infinity
Python (uv)uv tree
Python (pip)pipdeptree
Gogo mod graph
Rustcargo tree
Mavenmvn dependency:tree
Gradlegradle dependencies

Um herauszufinden, warum ein einzelnes Paket vorhanden ist, fragen Sie den Pfad dorthin ab: npm explain <package>, pnpm why, yarn why oder cargo tree -i <crate>. Wenn Sie mit den Pfaden arbeiten möchten, statt sie nur auszugeben, siehe Abhängigkeitsgraphen.

So beheben Sie eine verwundbare transitive Abhängigkeit

  1. Das übergeordnete Paket aktualisieren. Suchen Sie die direkte Abhängigkeit, die das Paket nachzieht, und wechseln Sie zu einem Release, das eine korrigierte Version verlangt. Das ist die sauberste Lösung, weil die Maintainer des übergeordneten Pakets sie getestet haben.
  2. Das Lockfile auffrischen. Wenn der Versionsbereich des übergeordneten Pakets die korrigierte Version bereits zulässt, genügt es, den Lockfile-Eintrag zu aktualisieren, zum Beispiel mit cargo update -p <crate> oder einem frischen npm update.
  3. Die Version überschreiben. Wenn das übergeordnete Paket noch keinen Fix ausgeliefert hat, erzwingen Sie die Version selbst: overrides in npm und pnpm, resolutions in Yarn, eine Constraints-Datei bei pip oder eine höhere Anforderung in go.mod. Testen Sie das, denn das übergeordnete Paket wurde nie mit dieser Version veröffentlicht.
  4. Das übergeordnete Paket ersetzen oder entfernen. Wenn beides nicht funktioniert, lohnt es sich vielleicht nicht mehr, die Abhängigkeit zu behalten, die das Paket mitbringt.

Manche Tools für Software Composition Analysis ergänzen eine Erreichbarkeitsanalyse, die prüft, ob Ihr Code die verwundbare Funktion überhaupt aufrufen kann, um zu entscheiden, welcher dieser Fixes zuerst kommt. Die Optionen finden Sie unter SCA-Tools im Vergleich.

Warum das Lockfile nicht die ganze Wahrheit ist

Die meisten Tools bauen ihre Sicht auf transitive Abhängigkeiten aus dem Lockfile auf. Das funktioniert, wenn das Lockfile vorhanden und aktuell ist und der Build aus nichts anderem installiert. Im CI ist das oft nicht der Fall:

  • Kein Lockfile. Eine requirements.txt mit Versionsbereichen oder ein Projekt, das sein Lockfile nie committet hat, wird bei jedem Build neu aufgelöst, sodass sich die transitiven Versionen zwischen Builds ändern können.
  • Caches. CI-Caches stellen Pakete aus früheren Läufen wieder her, statt sie zu laden, und was sie enthalten, entspricht nicht immer dem aktuellen Lockfile. Siehe was der GitHub-Actions-Cache verbirgt.
  • Build-Tools. Linter, Compiler, Codegeneratoren und Setup-Schritte bringen eigene Abhängigkeitsbäume in den Build. Sie stehen nicht im Manifest Ihrer Anwendung, laufen aber mit Zugriff auf Ihren Quellcode und Ihre Secrets.
  • Install-Skripte und Downloads. Das Install-Skript eines Pakets kann weiteren Code laden, und ein Build-Schritt kann direkt eine Binärdatei herunterladen. Beides hinterlässt keinen Eintrag in einem Lockfile.

Die einzige vollständige Aufzeichnung dessen, welche transitiven Abhängigkeiten in ein Release eingeflossen sind, entsteht, während dieses Release gebaut wird. SBOMs zur Build-Zeit erklärt den Unterschied zwischen dem Aufzeichnen eines Builds und dem nachträglichen Scannen seiner Dateien.

Transitive Abhängigkeiten und der CRA

Der EU Cyber Resilience Act verlangt von Herstellern eine SBOM, die „zumindest die obersten Abhängigkeiten der Produkte“ erfasst (Anhang I Teil II Nummer 1). Transitive Abhängigkeiten werden nicht genannt, die gesetzliche Untergrenze liegt also niedriger, als viele Leitfäden nahelegen. Der CRA verlangt aber auch, Schwachstellen in den Komponenten Ihres Produkts zu ermitteln und zu behandeln, und ein verwundbares transitives Paket ist eine davon. Eine SBOM, die bei der ersten Ebene aufhört, lässt den Großteil Ihres Abhängigkeitsbaums aus diesem Prozess heraus. Details finden Sie unter SBOM-Anforderungen des CRA.

Wie CRACI transitive Abhängigkeiten verfolgt

CRACI ist ein GitHub-Actions-Runner, der den Build aufzeichnet, statt ihn zu scannen. Während jeder Job läuft, zeichnet ein paketbewusster Proxy jedes Paket auf, das der Job lädt, auf jeder Ebene des Baums und einschließlich der aus CI-Caches wiederhergestellten Pakete. Das ergibt ein vollständigeres Bild der genutzten Abhängigkeiten als scannerbasierte Tools liefern.

  • Jede Ebene, ehrlich ausgewiesen. Die SBOM jedes Jobs trägt einen Vollständigkeitsstatus, sodass Sie wissen, wann eine Aufzeichnung nicht alles sehen konnte.
  • Der Baum, sichtbar. Ein Abhängigkeitsgraph zeigt die Abhängigkeitsebenen der SBOM, in mehreren Ansichten.
  • Exporte, die sie enthalten. CycloneDX- und SPDX-Exporte enthalten transitive Abhängigkeiten, jede mit ihrer deklarierten Lizenz.
  • Welche Builds betroffen waren. Wenn eine neue Schwachstelle auftaucht, zeigt die Build-Historie, welche früheren Builds das verwundbare Paket enthielten, direkt oder transitiv, sodass Sie wissen, in welchem Zeitraum Sie es ausgeliefert haben (siehe Sind wir von einer CVE betroffen?). Die Historie richtet sich nach Ihrer Aufbewahrungsfrist, standardmäßig 180 Tage.
  • Policy-Gates. Ein Build, der eine bestimmte CVE enthält, lässt sich blockieren, bevor er ausgeliefert wird.

CRACI macht keine Erreichbarkeitsanalyse. Wenn Sie wissen müssen, ob Ihr Code eine verwundbare Funktion aufruft, kombinieren Sie es mit einem SCA-Tool, das dies leistet. Siehe SBOM-Generierung in CRACI oder buchen Sie eine Demo, um einen Ihrer eigenen Builds aufzuzeichnen.

Transitive Abhängigkeiten: häufig gestellte Fragen

Was ist eine transitive Abhängigkeit?

Eine transitive Abhängigkeit ist ein Paket, das Ihre Software nutzt, weil ein anderes Paket es braucht. Wenn Ihre App von Bibliothek A abhängt und A von Bibliothek B, dann ist B eine transitive oder indirekte Abhängigkeit Ihrer App. Sie haben sie nie deklariert, aber sie wird mit Ihrer Software ausgeliefert.

Was ist der Unterschied zwischen einer direkten und einer transitiven Abhängigkeit?

Eine direkte Abhängigkeit deklarieren Sie in Ihrem Manifest, etwa package.json, pyproject.toml oder go.mod. Eine transitive Abhängigkeit deklarieren Ihre direkten Abhängigkeiten, in beliebiger Tiefe. Direkte Abhängigkeiten wählen Sie aus; transitive wählt der Paketmanager, wenn er den Baum auflöst.

Ist eine transiente Abhängigkeit dasselbe wie eine transitive Abhängigkeit?

Ja, in der Praxis. „Transiente Abhängigkeit“ ist ein häufiger Versprecher für „transitive Abhängigkeit“. Der korrekte Begriff ist transitiv, nach der transitiven Relation: Wenn A von B abhängt und B von C, dann hängt A von C ab.

Wie behebe ich eine Schwachstelle in einer transitiven Abhängigkeit?

Aktualisieren Sie zuerst die direkte Abhängigkeit, die sie nachzieht, sofern es ein Release mit einer korrigierten Version gibt. Falls nicht, erzwingen Sie die korrigierte Version mit dem Override-Mechanismus Ihres Paketmanagers, etwa npm overrides, Yarn resolutions oder einer pip-Constraints-Datei, und testen Sie, ob das übergeordnete Paket damit noch funktioniert.

Wie liste ich alle transitiven Abhängigkeiten auf?

Jeder Paketmanager kann den aufgelösten Baum ausgeben: npm ls --all, pnpm list --depth Infinity, uv tree oder pipdeptree, go mod graph, cargo tree, mvn dependency:tree oder gradle dependencies. Für das, was ein Produktions-Build tatsächlich installiert hat, zeichnen Sie den Build selbst auf.

Verlangt der EU Cyber Resilience Act transitive Abhängigkeiten in der SBOM?

Die Verordnung setzt die Untergrenze bei „zumindest die obersten Abhängigkeiten der Produkte“ (Anhang I Teil II Nummer 1). Transitive Abhängigkeiten werden nicht genannt, aber ein verwundbares transitives Paket steckt trotzdem in Ihrem Produkt, und der CRA verlangt, dass Sie Schwachstellen in den ausgelieferten Komponenten behandeln.

Sehen Sie jede Abhängigkeit, die Ihr Build geladen hat

Lassen Sie einen GitHub-Actions-Workflow auf CRACI laufen und erhalten Sie eine aufgezeichnete SBOM jedes geladenen Pakets, auf jeder Ebene des Baums.

Demo buchen