2025 markiert das Jahr, in dem Supply-Chain-Sicherheit kein theoretisches Risiko mehr ist, sondern zu einem praktischen Albtraum für alle geworden ist, die eine package.json-Datei verwalten.
Die jüngsten Angriffswellen auf das NPM-Ökosystem haben dies eindrucksvoll gezeigt: Vertrauenswürdige Bibliotheken wurden zu Angriffsvektoren, die Pipelines kompromittierten, noch bevor der Code überhaupt in Produktion gelangte.
Zunächst zeigte die Kompromittierung einiger beliebter NPM-Pakete, darunter chalk und debug, wie leicht ein Phishing-Angriff auf einen einzelnen Entwickler weitreichende Folgen haben kann. Nur eine Woche später brachte die erste Shai-Hulud-Welle einen sich selbst replizierenden Wurm und den groß angelegten Credential-Diebstahl von Entwickler-Rechnern mit sich. Vor kurzem trieb Shai-Hulud 2 (alias Sha1-Hulud) diese Strategie auf die Spitze und fügte das perfide Verhalten hinzu, Benutzerdateien zu löschen, falls ein Versuch unternommen würde, die Angriffswelle zu stoppen.
Wie können Entwicklungs- und Security-Teams diese Situation angehen und Kompromittierungen erkennen? Die Diskussion dieser Frage führt in der Regel zu Software Composition Analysis (SCA) mittels Abhängigkeitsanalyse und/oder Software Bills of Materials (SBOMs). Sobald man alle Abhängigkeiten kennt, sollte es einfach sein, kompromittierte Komponenten automatisch zu identifizieren und davon ausgehend mit der Behebung der Schwachstellen zu beginnen.
Im Fall von Shai-Hulud weist dieser Ansatz einige inhärente Einschränkungen auf:
- Die schädliche Payload muss nicht als Teil eines Releases ausgerollt werden, sondern wird bereits während des Build-Prozesses ausgeführt. Das bedeutet, dass jede Ausführung ein Risiko darstellen kann, einschließlich CI-Pipelines für jeden beliebigen Branch. SCA läuft jedoch häufig nur auf dem Main-Branch oder auf Release-Artefakten.
- Da zu den Zielen der Malware auch Entwickler*innen-Rechner gehören, muss sie lediglich lokal installiert werden, fernab von den Umgebungen, in denen SCA normalerweise durchgeführt wird.
Trotz dieser Einschränkungen wäre zu erwarten, dass SCA als eine Verteidigungslinie dient und wertvolle Einblicke in die Ausbreitung der kompromittierten Pakete liefert.
Bewertung von Tools zur Überprüfung von Abhängigkeiten
Als ich Trivy auf einem mutmaßlich betroffenen Projekt ausführte, war ich überrascht, dass es keine Probleme identifizieren konnte. Ich habe daraufhin eine Umfrage auf Mastodon gestartet, um herauszufinden, ob ich etwas übersehen hatte:
Von den 50 Teilnehmenden teilte die Mehrheit (68 %) meine eigenen Erwartungen.
Dies veranlasste uns, genauer hinzuschauen und das Verhalten der beliebtesten Open-Source-Tools für SCA und Dependency Scanning zu untersuchen: Neben Trivy von Aqua Security gehören dazu Grype von Anchore, OSV-Scanner von Google und OWASP Dependency-Track. Aufgrund ihrer eingeschränkten Verfügbarkeit haben wir kommerzielle Tools wie Snyk, Aikido oder GitLab Ultimate Dependency Scanning nicht untersucht.
Für diesen Vergleich habe ich ein Demo-Projekt mit betroffenen Versionen von ansi-regex und kill-port eingerichtet:
1{ 2 "dependencies": { 3 "ansi-regex": "6.2.1", 4 "kill-port": "2.0.2" 5 } 6}
ansi-regex war betroffen von der ersten großen Welle an Kompromittierungen von NPM-Paketen im September 2025, während kill-port im Rahmen von Shai-Hulud 2 kompromittiert wurde.
Da diese Versionen schnell aus NPM entfernt worden waren (und natürlich Malware enthielten), haben wir sie nicht tatsächlich installiert, sondern fingierte package.json- und package-lock.json-Dateien aufgesetzt.
Wir haben verifiziert, dass alle Scanner diese fingierten Versionen anhand der Metadaten-Dateien erkannt haben.
Sofern nicht anders angegeben, wurden die Standardkonfigurationen aller Tools verwendet. Alle Tests wurden mit den aktuellen Schwachstelleninformationen vom 2025-12-03 durchgeführt.
Trivy
Wie oben erwähnt, hat Trivy keinerlei Probleme festgestellt.
Dies galt sowohl für das direkte Scannen des Projekts (trivy fs) als auch für das Scannen einer vorab generierten SBOM (trivy sbom):
Report Summary
┌───────────────────┬──────┬─────────────────┐
│ Target │ Type │ Vulnerabilities │
├───────────────────┼──────┼─────────────────┤
│ package-lock.json │ npm │ 0 │
└───────────────────┴──────┴─────────────────┘
Grype
Grype stufte beide Probleme als kritisch ein, wenn es auf der mit Trivy generierten SBOM ausgeführt wurde (grype bom.json):
NAME INSTALLED TYPE VULNERABILITY SEVERITY EPSS RISK
ansi-regex 6.2.1 npm GHSA-jvhh-2m83-6w29 Critical N/A N/A
kill-port 2.0.2 npm GHSA-3j2r-p9f6-rw66 Critical N/A N/A
Bei der direkten Ausführung auf den Projektordner (grype .) fand es die Probleme ebenfalls, allerdings gab es auch viele False-Positives:
NAME INSTALLED FIXED IN TYPE VULNERABILITY SEVERITY EPSS RISK
json5 1.0.1 1.0.2 npm GHSA-9c47-m6qq-7p4h High 37.3% (97th) 27.2
json5 2.2.1 2.2.2 npm GHSA-9c47-m6qq-7p4h High 37.3% (97th) 27.2
trim-newlines 1.0.0 3.0.1 npm GHSA-7p7h-4mm5-852v High 1.3% (78th) 0.9
# [...]
ansi-regex 6.2.1 npm GHSA-jvhh-2m83-6w29 Critical N/A N/A
kill-port 2.0.2 npm GHSA-3j2r-p9f6-rw66 Critical N/A N/A
Man beachte die Warnungen mit hoher Severity für json5 und trim-newlines.
Diese (und viele andere, nicht aufgeführte) sind vorhanden, weil Grype in das Verzeichnis node_modules abgestiegen ist, die package.json-Metadaten aller Module gelesen und deren devDependencies fälschlicherweise als Teil unseres Projekts identifiziert hat.
Dies ließe sich wahrscheinlich durch eine Konfiguration beheben, aber wir blieben bei der Standardeinstellung und haben uns nicht weiter damit befasst.
OSV-Scanner
Der OSV-Scanner schnitt (fast) perfekt ab und identifizierte die Probleme sowohl direkt im Projektverzeichnis als auch in der SBOM von Trivy. Allerdings konnte er keine Angaben zur Schwere der Probleme oder zu behobenen Versionen liefern:
╭─────────────────────────────────┬──────┬───────────┬────────────┬─────────┬───────────────┬──────────╮
│ OSV URL │ CVSS │ ECOSYSTEM │ PACKAGE │ VERSION │ FIXED VERSION │ SOURCE │
├─────────────────────────────────┼──────┼───────────┼────────────┼─────────┼───────────────┼──────────┤
│ https://osv.dev/MAL-2025-46966 │ │ npm │ ansi-regex │ 6.2.1 │ -- │ bom.json │
│ https://osv.dev/MAL-2025-191116 │ │ npm │ kill-port │ 2.0.2 │ -- │ bom.json │
╰─────────────────────────────────┴──────┴───────────┴────────────┴─────────┴───────────────┴──────────╯
OWASP Dependency-Track
Schauen wir uns zum Schluss noch OWASP Dependency-Track an. Im Gegensatz zu den anderen Tools wird es nicht über die Kommandozeile aufgerufen, sondern läuft als Webanwendung. Es kann auch keine eigene Composition Analysis durchführen, sondern benötigt immer eine vorhandene SBOM. Zu diesem Zweck habe ich erneut die SBOM-Datei von Trivy verwendet.
In seiner Standardkonfiguration konnte Dependency-Track keine Schwachstellen identifizieren:
Allerdings kann man bei Dependency-Track die Datenquellen für Schwachstelleninformationen konfigurieren. Neben dem integrierten NVD-CVE-Feed gehören zu den öffentlich verfügbaren zusätzlichen Optionen GitHub Advisories und Open Source Vulnerabilities (OSV, die Datenquelle hinter OSV-Scanner).
Die Aktivierung von GitHub Advisories brachte keine Änderungen mit sich, weiterhin wurden keinerlei Schwachstellen erkannt. Obwohl sich die OSV-Datenquelle noch im Beta-Stadium befindet, machte ihre Aktivierung tatsächlich einen Unterschied:
Erkundung der Datenquellen
Auf welche verschiedenen Quellen für Schwachstelleninformationen greifen Tools zur Abhängigkeitsanalyse in der Regel zu?
Die bekannteste Quelle ist das NVD „Common Vulnerabilities and Exposures“-Programm, auch bekannt als CVE-Datenbank. Abgesehen von den anhaltenden allgemeinen Problemen mit der Datenqualität gibt es hier einen entscheidenden Haken für kompromittierte NPM-Pakete: Für (fast?) alle davon hat sich niemand die Mühe gemacht, CVEs zu vergeben! Wir können diese Datenquelle daher für die Identifizierung von Shai-Hulud und Ähnlichem ausschließen.
GitHub, das zufällig auch die NPM Paket-Registry betreibt, stellt eine eigene Security-Advisory-Datenbank (GHSA) bereit.
Wann immer GitHub eine kompromittierte Paketversion entfernt hat, wurde dazu auch ein entsprechendes Advisory veröffentlicht.
Dabei handelt es sich jedoch um spezielle Malware-Advisories, die daher gut versteckt sind:
Um sie zu finden, muss man den speziellen Filter type:malware zur Suchanfrage hinzufügen.
GitHub begründet dies wie folgt:
Our malware advisories are mostly about substitution attacks. During this type of attack, an attacker publishes a package to the public registry with the same name as a dependency that users rely on from a third party or private registry, with the hope that the malicious version is consumed. [...] Users who have their dependencies appropriately scoped should not be affected by malware.
Während dieses Argument bei Substitutionsangriffen Sinn ergibt, greift es zu kurz, sobald echte, vertrauenswürdige Pakete mit Malware kompromittiert werden.
Malware-Advisories werden standardmäßig nicht von der GHSA-API zurückgegeben, was wahrscheinlich der Grund dafür ist, dass sie von OWASP Dependency-Track und Trivy (das ebenfalls GHSA als Datenquelle für NPM-Pakete verwendet) nicht erfasst werden. Grype scheint dies anders zu handhaben und bezieht die Malware-Advisories standardmäßig mit ein.
Die dritte wichtige Datenquelle ist Googles Open Source Vulnerabilities (OSV)-Projekt. Zwar aggregiert es „nur“ Schwachstelleninformationen aus anderen Quellen, darunter GHSA, doch umfasst sein Haupt-Feed auch die Malware-Advisories von GitHub. Von dort gelangen die Informationen schließlich zu OSV-Scanner und (optional) OWASP Dependency-Track.
Manche mögen argumentieren, dass Malware-Infektionen nicht Teil von Schwachstellendatenbanken sein sollten, da es sich hierbei nicht um ausnutzbare Schwachstellen handelt, sondern um Fälle, in denen die Kompromittierung bereits in der Lieferkette stattgefunden hat. Wir betrachten das als eine rein theoretische Unterscheidung. Dies wird durch die Tatsache gestützt, dass es tatsächlich einen CWE-Eintrag (Common Weakness Enumeration, ein Kategorisierungssystem aus dem CVE-Ökosystem) für die Replikation von Schadcode gibt.
Letztendlich sind diese Abhängigkeiten offenkundig unsicher. Natürlich wollen wir über einen Sicherheitslücken-Feed davon erfahren! Eher noch ist das Risiko höher als bei einem anfälligen, aber nicht angegriffenen Paket.
Endpoint-Schutz als Rettung?
Sollten wir angesichts der eingangs erwähnten Einschränkungen und der eher durchwachsenen Ergebnisse von Dependency-Scannern auf eine andere Verteidigungslinie umsteigen? Schließlich geht ein Großteil des Risikos bei den Shai-Hulud-Angriffen davon aus, dass die Malware auf den Rechnern der Entwickler*innen installiert wird. Könnte eine Endpoint-Protection-Lösung (Antivirus/EDR) diese nicht identifizieren und weiteren Schaden verhindern?
Um diese Idee zu überprüfen, habe ich auf Mastodon eine weitere Umfrage durchgeführt, in der die Mehrheit mich erneut bestätigte:
Da sich Endpoint-Schutz bekanntlich schwer testen lässt, haben wir uns die Ergebnisse von VirusTotal für die bekannten Payloads von Shai-Hulud 2 angesehen. VirusTotal überprüft in erster Linie statische Signaturen, während ein fortschrittliches EDR-System im Idealfall das bösartige Verhalten erkennen würde. Wenn die Dateisignatur jedoch nicht einmal als verdächtig markiert wird, ist die erste Verteidigungslinie bereits durchbrochen. Schließlich lässt sich die Erkennung in diesem Fall darauf herunterbrechen, Dateien mit einigen wenigen, bekannten Prüfsummen zu identifizieren.
Das war das Ergebnis für eine der schädlichen Dateien am 2025-11-26, zwei Tage nach der ersten Erkennung:
Wenn man die Live-Ergebnisse betrachtet, sieht man, dass sich die Erkennungsraten zwar leicht verbessert haben, einige große Anbieter das Problem aber immer noch nicht erkennen.
Noch düsterer sah es für eine weitere der bösartigen Payloads am 2025-11-26 aus:
Auch in diesem Fall haben sich die Live-Ergebnisse zwischenzeitlich verbessert, doch wird die Malware von etwa der Hälfte der Scanner immer noch nicht erkannt.
Fazit
Während GitHub als Betreiber von NPM die von groß angelegten Angriffen betroffenen Paketversionen zügig entfernt hat (zumindest in den meisten Fällen), bietet der Informationsaustausch drumherum noch Raum für Verbesserungen – von Hinweisen auf den NPM-Seiten der Pakete bis hin zur Veröffentlichung (der richtigen Art) von Security Advisories. Dies macht den Einsatz von Dependency-Scannern weniger zuverlässig, als er sein könnte, und führt dazu, dass die Erkennung stark von den jeweils verwendeten Datenquellen abhängt.
Wir waren überrascht, wie viele Scanner die Kompromittierungen nicht identifizieren konnten, sei es auf der Ebene der SCA oder der der Endpunkte. Zwar identifizieren die richtigen Scanner die Probleme in der Regel oder lassen sich zumindest entsprechend konfigurieren, doch ist dies nicht ohne Tücken, und nicht jedes Produkt liefert ein zufriedenstellendes Ergebnis. Dies ist besonders besorgniserregend angesichts der großen Auswirkungen und der breiten Aufmerksamkeit, die die jüngsten NPM-Kompromittierungen auf sich gezogen haben. Man kann sich nur fragen, was im Falle subtilerer Attacken geschieht, die weniger öffentliche Aufmerksamkeit erhalten.
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
Blog-Autor*in
Felix Dreißig
Information Security Specialist
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.