Die Kurzfassung
Der Shai-Hulud-npm-Angriff kehrte am 4. August 2026 zurück und gelangte über keyv und die cacheable Familie von Caching-Bibliotheken und verbreitete sich anschließend eigenständig auf Hunderte weiterer Pakete. Es handelt sich um einen sich selbst replizierenden Credential-Stealer. Forscher, die das Programm analysierten, stellten fest, dass sich die Kampagne in den Beschreibungen der GitHub-Repositorys als „Shai-Hulud: Here We Go Again“ identifizierte, was sie in dieselbe Linie wie die npm-Supply-Chain-Angriffe vom September 2025 und die Die Kampagnen „Shai-Hulud“ und „Megalodon“, die wir im Juni analysiert haben.
Die Zahlen variieren je nachdem, wer wann die Erhebung durchgeführt hat. JFrog dokumentierte mehr als 400 Pakete in über 1.700 Versionen. CyberScoop berichtete, dass die erste Welle in weniger als vier Stunden 440 Pakete umfasste und die Gesamtzahl schließlich 860 Pakete überstieg, die zusammen monatlich zwei Milliarden Installationen verzeichneten. Man kann also von mehr als 400 Paketen ausgehen, nach manchen Schätzungen sogar von mehr als 800.
Die Zahl, die man im Auge behalten sollte, ist nicht die Anzahl der Pakete. Es sind die vier Stunden. Ein Betreuerkonto wurde gehackt, und innerhalb eines einzigen Nachmittags hatte sich der Angriff auf Hunderte von Projekten ausgebreitet, die nichts miteinander zu tun hatten und deren Betreiber nichts falsch gemacht hatten und keine Möglichkeit hatten, davon zu erfahren.
Was diese Kampagne für eine Untersuchung besonders interessant macht, ist die Tatsache, dass sie über zwei völlig unterschiedliche Zugänge erfolgte, auf die die meisten Abwehrmaßnahmen der Branche nicht ausgerichtet sind. Um Zugang zu erhalten, musste ein Maintainer kompromittiert und bösartiger Code in einen Quellcode-Baum eingeschleust werden. Für die Verbreitung war das Schreiben von Code überhaupt nicht erforderlich. Es bedurfte lediglich der Möglichkeit, Inhalte zu veröffentlichen.
Das sind zwei verschiedene Probleme. Sie erfordern zwei verschiedene Lösungen.
Bin ich von dem Shai-Hulud-npm-Angriff betroffen?
Fangen Sie hier an, bevor Sie irgendetwas anderes lesen.
Es besteht ein potenzielles Sicherheitsrisiko, wenn Sie oder Ihre CI eine beliebige Version von keyv, cacheable, cacheable-request, cache-manager, flat-cache, file-entry-cache, oder alles unter der @cacheable Gültigkeitsbereich ab dem 4. August 2026. Die bisher dokumentierten Freisetzungen von Giftstoffen sind keyv 6.0.0, cacheable 2.5.1, @cacheable/memory 2.2.1, @cacheable/net 2.1.1, @cacheable/node-cache 3.1.2 und @cacheable/utils 2.5.1 laut der Analyse von JFrog, mit cache-manager 7.2.10 und cacheable-request 13.0.20 bestätigt durch Wiz. CyberScoop berichtet flat-cache und file-entry-cache innerhalb von etwa dreißig Minuten nach der ersten Veröffentlichung. Überprüfen Sie, was in Ihrer eigenen Lockdatei aufgeführt ist, da jede veröffentlichte Liste zum Zeitpunkt der Veröffentlichung noch weiter anwuchs.
Sie sind durch die zweite Welle gefährdet, wenn Sie Produkte aus dem Sortiment unter der @onereach, @or-sdk, @nebula.js, @qlik, @ornikar oder @servicetitan scopes oder eines der mehreren hundert anderen Pakete, deren Betreuer über npm-Token verfügten, die sich auf einem vom Wurm befallenen Rechner befanden. Betrachten Sie jede am 4. August oder danach durchgeführte npm-Installation als verdächtig, bis Sie überprüft haben, was dabei tatsächlich aufgelöst wurde.
Ein Detail schränkt den Explosionsradius erheblich ein. Die Nutzlast stammte von einem npm preinstall Lebenszyklus-Hook, und ab npm 12 werden diese Hooks standardmäßig nicht mehr ausgeführt. Wenn Ihre Build-Server und Entwicklerrechner unter der Standard-Skriptrichtlinie mit npm 12 oder neuer laufen oder Sie die Installation mit --ignore-scripts, wäre der Dropper nicht ausgeführt worden, selbst wenn das manipulierte Tarball-Archiv in node_modules, es sei denn, die Lebenszyklus-Skripte waren für diese Pakete ausdrücklich wieder aktiviert worden. JFrog weist ausdrücklich darauf hin, und dies ist die mit Abstand nützlichste positive Nachricht im Zusammenhang mit diesem Vorfall.
Ein Detail vergrößert es. keyv und flat-cache sind keine Pakete, für die sich die meisten Teams entscheiden. Sie tauchen als transitive Abhängigkeiten von ESLint und HTTP-Client-Bibliotheken auf, mehrere Ebenen tiefer, in Projekten, die gar nicht wissen, dass sie dort vorhanden sind.
Aus diesem Grund hatte dieser Angriff eine größere Reichweite als seine Vorgänger. Von CyberScoop zitierte Daten von Wiz Telemetry ergaben, dass das am häufigsten vorkommende der kompromittierten Pakete in rund 46 Prozent der von ihnen erfassten Cloud-Umgebungen vorhanden war, gegenüber etwa 28 Prozent bei der früheren Shai-Hulud-2.0-Welle. Der Shai-Hulud-npm-Angriff erlangte seine Reichweite dadurch, dass er über eine Infrastruktur eindrang, an die niemand denkt.
Wie sich der Shai-Hulud-npm-Angriff abspielte
Der Einstiegspunkt war das GitHub-Konto eines Betreuers. Wiz beschreibt das keyv und cacheable Pakete, die „nach dem Hackerangriff auf das Konto eines GitHub-Betreuers, der zur Veröffentlichung bösartiger Paketversionen führte“, kompromittiert wurden, und beschreibt den Ablauf der Ereignisse: Der Angreifer nutzte zunächst die kompromittierte Identität, um Persistenz-Payloads in die IDE einzuschleusen, und keyv Repository selbst und veröffentlichte kurz darauf eine neue Version von keyv die Nutzlast transportierend.
Diese Reihenfolge ist entscheidend. Der Code wurde erst in das Projekt aufgenommen, bevor er in das Repository gelangte; daher erfolgte die Veröffentlichung bei npm im Rahmen des projektinternen Veröffentlichungsprozesses und nicht außerhalb davon. Soweit dieser Prozess erkennen konnte, hatte eine autorisierte Person Code in das Repository eingespielt und eine Version veröffentlicht. Genau dafür ist dieser Prozess ja da.
In jedes Paket wurden zwei Dateien gepackt. Die erste, setup.mjs, ist ein kleiner, verschleierter Dropper, der in package.json als "preinstall": "node setup.mjs". Es enthält keine Nutzlast. Es lädt die Bun-JavaScript-Laufzeitumgebung herunter, entpackt sie und nutzt sie, um die zweite Datei auszuführen: etwa 710 bis 728 Kilobyte stark verschleiertes JavaScript mit dem Namen math_init.js in einigen Paketen und Math_Symbol.js in anderen.
Die Entscheidung, auf „Bun“ statt auf die bereits vorhandene Node-Laufzeitumgebung zurückzugreifen, ist bewusst getroffen worden. Dadurch erhält die Nutzlast eine vorhersehbare Ausführungsumgebung, unabhängig von der Node-Version des Opfers, und die eigentliche Arbeit wird in einem Prozess ausgeführt, der vom Paketmanager nicht überwacht wird.
Die erste Tür: ein vergifteter Quellbaum
Für keyv und die cacheable Pakete: Der Schadcode befand sich im Upstream-Git-Repository. Das ist von größerer Bedeutung, als es zunächst den Anschein hat.
Das bedeutet, dass der Kompromiss alles übersteht, was auf der Annahme basiert, dass der Quellcode vertrauenswürdig ist und nur das veröffentlichte Artefakt verdächtig ist. Wenn man aus dem Quellcode neu kompiliert, erstellt man die Hintertür erneut. Wenn man das Artefakt anhand des Quellcodes überprüft, wird es bestätigt. Überprüft man die Herkunftsbescheinigung, so ist diese echt, da der Build tatsächlich in dem angegebenen Workflow und ausgehend von dem angegebenen Commit stattgefunden hat. Die Bescheinigung verknüpft das Artefakt mit einem Quellcode und einem Build-Prozess, und beides war echt; der Quellcode war lediglich bereits manipuliert.
Die Kampagne führte diese Argumentation bis zum Äußersten durch – allerdings gegen ein anderes Ziel. JFrog entdeckte eine auf OpenSearch ausgerichtete Sonderfalllogik opensearch-js Repository, das GitHub Actions OIDC für die vertrauenswürdige Veröffentlichung nutzt: innerhalb eines Workflow-Laufs, dessen Repository opensearch-js und dessen GITHUB_WORKFLOW_REF abgestimmt release-drafter.yml, die Nutzlast forderte ein Actions-OIDC-Token an, dessen Geltungsbereich auf npm:registry.npmjs.org, tauschte es gegen ein Veröffentlichungstoken ein, veröffentlichte ein bösartiges Tarball-Archiv und generierte mithilfe von Fulcio und Rekor ein Sigstore-Bundle, sodass das Ergebnis eine gültige Herkunft aus einem vertrauenswürdigen Workflow-Kontext aufwies.
Der zuverlässigste Schutz gegen diese Sicherheitslücke ist, dass jemand oder etwas den Diff ausliest.
Die zweite Tür: 400 Pakete, für die niemand Code geschrieben hat
Hier hat die Kampagne an Umfang gewonnen, und hier unterscheiden sich die Spielmechaniken vom Einstiegspunkt in einer Weise, die Auswirkungen darauf hat, womit man sich gegen sie verteidigen kann.
Die Payload sammelt npm-Token aus ~/.npmrc und gleicht sie mit der Registrierungsdatenbank ab. Wenn es ein Token findet, das über Schreibrechte verfügt, und bypass_2fa Wird dieser Wert auf „true“ gesetzt, führt die Routine Folgendes aus – ich zitiere hier die Beschreibung von JFrog: Sie lädt die aktuelle latest Tarball, kopiert das laufende Beispiel nach package/math_init.js, schreibt der Loader in package/setup.mjs, ersetzt das gesamte Paket scripts Objekt und Mengen scripts.preinstall zu node setup.mjs, erhöht die Patch-Version, erstellt anschließend ein neues Paket und veröffentlicht es mit einer direkten, authentifizierten PUT in die npm-Registry.
Lesen Sie diese Abfolge noch einmal durch und achten Sie darauf, was fehlt. Kein Commit. Kein Pull-Request. Kein CI-Lauf. Kein Repository-Zugriff jeglicher Art. Der Quellcode-Baum jedes einzelnen dieser mehreren hundert sekundären Pakete war die ganze Zeit über sauber und ist es immer noch, da der Schadcode ausschließlich in einem Tarball vorhanden war, der auf dem Rechner des Angreifers zusammengestellt und mit gestohlenen Zugangsdaten direkt in das Registry hochgeladen wurde.
Das macht den Großteil dieses Vorfalls gemessen an der Anzahl der Pakete aus: Hunderte von Betreuern, deren Repositorys nie angefasst wurden, deren Code-Review nie umgangen wurde, deren CI nie etwas Ungewöhnliches festgestellt hat und deren Nutzer trotzdem Malware installiert haben.
Was die Nutzlast mitnahm
Der Credential-Collector ist so umfassend, dass der Eindruck entsteht, es handele sich um eine Liste, die im Laufe mehrerer Kampagnen zusammengestellt wurde, anstatt speziell für diese eine erstellt worden zu sein. Er durchläuft Hunderte von konfigurierten Pfaden unter Linux, macOS und Windows und erfasst dabei Token von Paketmanagern, Cloud-Anmeldedaten aus Konfigurationsdateien und Instanz-Metadatendiensten, Kubernetes-Dienstkontotoken, den gesamten HashiCorp Vault KV-Speicher, SSH-Schlüssel, VPN-Profile, im Browser gespeicherte Anmeldedaten, Stripe- und Slack-Token sowie Schlüssel für KI-Dienste wie OpenAI, Anthropic, Cursor und Gemini.
Auf GitHub-Actions-Runner wird zudem der Prozessspeicher für Geheimnisse ausgegeben, die der Runner bereits entschlüsselt hat. Dahinter verbirgt sich eine Durchsuchung von mehr als 200 Glob-Mustern auf der Suche nach .env Dateien, private Schlüssel, Terraform-State-Dateien und KeePass-Datenbanken.
Die verschlüsselten Ergebnisse werden in öffentliche GitHub-Repositorys hochgeladen, die unter dem Konto des Opfers angelegt wurden und deren Beschreibungen dem Muster „Shai-Hulud: Here We Go Again“ entsprechen. Ox Security hat mehr als 800 solcher Repositorys gezählt, die auf GitHub auffindbar sind. Ein Ausweich-HTTP-Kanal verweist auf eine Domain, die am 22. Mai 2026 registriert wurde – mehr als zwei Monate, bevor sie genutzt wurde.
Ox Security berichtet zudem von einem Sabotagemechanismus, der in den anderen Berichten nicht beschrieben wird: Wird das gestohlene GitHub-Token widerrufen, gibt die Malware Löschbefehle für den infizierten Rechner aus. Betrachten Sie dies als Angabe eines einzelnen Anbieters, die nicht unabhängig bestätigt wurde, und berücksichtigen Sie dies jedoch bei der Planung Ihrer Abhilfemaßnahmen. Das Widerrufen von Zugangsdaten, bevor Sie den Host isoliert haben, kann Konsequenzen haben.
Es hat sich auch an Ihren Redakteur gewandt
Der GitHub-Teil der Verbreitung zielt eher auf die Rechner der Entwickler als auf die Registry ab, und genau dieser Teil ist es, der höchstwahrscheinlich noch immer unbemerkt in einem Repository irgendwo schlummert.
Mithilfe gestohlener persönlicher GitHub-Zugriffstoken überträgt die Payload fünf Dateien in bis zu 50 Branches pro Repository: .vscode/tasks.json, .vscode/setup.mjs, .claude/math_init.js, .claude/settings.json und .claude/setup.mjs. Die tasks.json Der Eintrag definiert eine Aufgabe mit dem Namen „Environment Setup“, die ausgeführt wird node .claude/setup.mjs, und die settings.json Eintrag registriert ein SessionStart Hook. Die Ausführung erfolgt, wenn ein Entwickler das Repository in VS Code öffnet oder eine KI-Codierungssitzung startet.
Die Commits tragen folgende Titel: chore: update config und enthalten eine gefälschte Angabe der Mitautoren, die sie folgenden Personen zuschreibt: [email protected]. Wenn das gestohlene Token auch Workflow-Berechtigungen enthält, schreibt die Nutzlast einen GitHub-Actions-Workflow, der Actions-Geheimnisse exfiltriert, indem er diese in ein Artefakt verpackt und dieses auf einen Zweig namens dependabot/github_actions/format/setup-formatter.
Jeder dieser Namen wurde so gewählt, dass er einer flüchtigen Überprüfung standhält. Ein Zweig, der wie „Dependabot“ aussieht, ein Workflow, der wie „CodeQL“ aussieht, ein Commit, der wie eine Konfigurationsbereinigung aussieht, ein Artefakt, das wie ein Formatierer aussieht, und eine Zeile mit Mitautoren, die wie ein KI-Assistent aussieht – all das wird mittlerweile von vielen Teams ganz legitim in ihre Repositorys eingecheckt.
Warum herkömmliche Scanner den „Shai-Hulud“-npm-Angriff übersehen haben
Die Tools, auf die sich die meisten Unternehmen verlassen, wurden entwickelt, um eine Frage zu beantworten, die dieser Angriff gar nicht stellt.
Schwachstellenscanner vergleichen Ihren Abhängigkeitsbaum mit Datenbanken bekannter CVEs. Am 4. August gab es noch keine CVE für keyv 6.0.0, daher gab es keine Übereinstimmung. Als die Sicherheitshinweise schließlich vorlagen, war das vierstündige Zeitfenster bereits abgelaufen und der Wurm hatte sich bereits weiterverbreitet.
Das ist keine Kritik an den Scannern. Die Erkennung bekannter Sicherheitslücken ist eine ganz andere Aufgabe, und diese erfüllen sie gut.
Auch die registrierungsseitigen Kontrollemechanismen für Konten erfüllten ihren Zweck. Die Zwei-Faktor-Authentifizierung schützt ein Veröffentlichungskonto vor Personen, die lediglich über ein Passwort verfügen. Sie schützt jedoch nicht vor einem von diesem Konto für Automatisierungszwecke generierten Token, und der Wurm suchte gezielt nach Token, die zur Umgehung der Zwei-Faktor-Authentifizierung gekennzeichnet waren – gerade weil es sich dabei um Token handelt, die ohne menschliches Zutun funktionieren. Viele automatisierte npm-Veröffentlichungskonfigurationen stützten sich in der Vergangenheit genau auf diese Art von Anmeldedaten: ein Token, mit dem Veröffentlichungen ohne menschliches Zutun durchgeführt werden können.
Herkunft und Signatur stellen den schwierigsten Fall dar, da sie in dieser Kampagne genau wie vorgesehen funktionierten und dennoch ein „grünes“ Ergebnis lieferten. Der OpenSearch-Versuch ist das deutlichste Beispiel: ein bösartiger Tarball, der über einen tatsächlich vertrauenswürdigen Workflow veröffentlicht wurde, zusammen mit einem Sigstore-Bundle, das über Fulcio und Rekor entsprechend erstellt wurde.
Die Herkunftsangabe beantwortet die Frage: „Stammt dieses Artefakt tatsächlich aus der angegebenen Quelle und dem angegebenen Verarbeitungsprozess?“, und die Antwort lautete „Ja“. Diese Frage ist es wert, beantwortet zu werden, und verliert hier nicht an Bedeutung. Ein grünes Häkchen gibt jedoch nur Auskunft darüber, woher ein Artefakt stammt, nicht aber darüber, ob das, was von dort stammt, sicher ist.
Die Erreichbarkeitsanalyse weist dieselbe Lückenform auf. Die Feststellung, dass ein anfälliger Codepfad niemals aufgerufen wird, ist hilfreich für die Priorisierung von CVE-Maßnahmen. A preinstall Der Hook muss von Ihrer Anwendung aus nicht erreichbar sein. Er wird im Rahmen der Installation der Abhängigkeit ausgeführt, noch bevor Ihre Anwendung ihn überhaupt aufruft.
Zwei Türen benötigen zwei verschiedene Schlösser
Die beiden Zugangswege in dieser Kampagne werden durch völlig unterschiedliche Faktoren unterbunden, daher lohnt es sich, genau zu unterscheiden, welcher TuxCare-Mechanismus welche Tür verschließt.
SecureChain für npm stellt Open-Source-Komponenten bereit, die TuxCare in seiner eigenen Build-Infrastruktur aus dem Quellcode neu kompiliert und in seinem eigenen Katalog veröffentlicht, wobei jedes Artefakt mit Herkunftsnachweisen und einer CycloneDX-SBOM versehen ist. Kunden richten ihren Paketmanager auf SecureChain statt auf das öffentliche Register aus, sodass TuxCare zur Standardquelle für die Auflösung ihrer Builds wird.
Es gibt zwei Möglichkeiten, dies umzusetzen: Entweder wird ausschließlich das verwendet, was im SecureChain-Katalog enthalten ist, oder man schaltet einen Registrierungsmanager davor, sodass alles, was noch nicht im Katalog enthalten ist, in die öffentliche Registrierung weitergeleitet wird.
Die zweite Tür schließt sich für die Veröffentlichungsrechte
Betrachten wir zunächst den Verbreitungsmechanismus, da er den größeren Teil des Vorfalls ausmacht und die Geschichte übersichtlicher ist. Die Vorgehensweise des Wurms bestand darin, ein veröffentlichtes Tarball-Archiv abzurufen, zwei Dateien einzuschleusen und die scripts Blockieren, die Patch-Version erhöhen und das Ergebnis mit einem gestohlenen Token in die Registry übertragen. Dieser Angriff erfordert vor allem eines: die Möglichkeit, eine neue Version eines Pakets an der Stelle zu platzieren, an der Ihr Resolver danach sucht.
Für jede Komponente im SecureChain-Katalog ist die Version, die Ihr Build auflöst, jene, die TuxCare aus dem Quellcode des jeweiligen Projekts in seiner eigenen CI erstellt hat. Das vom Angreifer erneut veröffentlichte Tarball befindet sich nicht in diesem Pfad, und auch durch noch so viele Veröffentlichungen im öffentlichen Register wird es dort nicht platziert. Die schädlichen Dateien in diesen mehreren hundert sekundären Paketen existierten ausschließlich in einem an npm übermittelten Tarball. Sie waren nie im Quellcode enthalten. Ein Build aus dem Quellcode reproduziert sie nicht, und es gibt nichts zu erkennen, da dort nichts vorhanden ist.
Der Mechanismus sollte klar dargelegt werden. Die Technik, die diese Kampagne in großem Maßstab ermöglicht hat, benötigt Zugriff auf die Veröffentlichungsdatenbank, aus der Ihr Build stammt. Handelt es sich dabei um das öffentliche Register, reicht ein gestohlenes Token aus. Handelt es sich um den SecureChain-Katalog, nützt ein gestohlenes npm-Token dem Angreifer nichts, da bei der Veröffentlichung auf npm keine Versionsnummer vor Ihrem Build steht.
Die erste Tür schließt sich beim Lesen der Diff
Der Einstieg ist ein schwierigeres Problem, und genau dieses hat die Branche bisher größtenteils vermieden, denn die ehrliche Antwort lautet: Jemand muss sich den Code ansehen.
SecureChain führt im Rahmen seiner Pipeline zur Einbindung neuer Pakete eine Erkennung von Schadcode durch. Der Detektor vergleicht die Unterschiede im Quellcode zwischen einer neuen Paketversion und der vorherigen Version und sucht dabei nach Verhaltensmustern, die auf eine Kompromittierung der Lieferkette hindeuten: verdächtige Ausführungen während der Build-Phase, Verschleierung, Datenexfiltration und andere Indikatoren für böswillige Absichten. Hooks für die Ausführung während der Build-Phase sind ausdrücklich im Untersuchungsumfang enthalten, der npm abdeckt preinstall und postinstall, Python setup.py Ausführungspfade und Aufrufe von Maven-Plugins.
Eine mit einem Kennzeichen versehene Version wird von der Veröffentlichung zurückgehalten. Sie wird nicht in den Katalog aufgenommen, was bedeutet, dass sie gar nicht erst in die Build-Umgebung eines Kunden gelangt.
Überlegen Sie einmal, was dieser Detektor am 4. August beobachtet hätte. Der Unterschied zwischen dem letzten sauberen keyv und keyv Version 6.0.0 enthält eine neue Datei namens setup.mjs, eine zweite neue Datei mit einer Größe von etwa 710 Kilobyte, die stark verschleiertes JavaScript enthält, sowie eine preinstall Eintrag, der in … erscheint package.json wo eine Caching-Bibliothek zuvor keine hatte.
Jedes dieser Merkmale ist ein Signal, auf das der Detektor ausgelegt ist: verschleierter Inhalt, der im Quellcode-Verzeichnis auftaucht, ein Ausführungs-Hook zur Build-Zeit, der an einer Stelle auftaucht, an der zuvor keiner vorhanden war, und beides in derselben Version einer Bibliothek, deren einzige Aufgabe darin besteht, Schlüssel-Wert-Paare zu speichern. Der Detektor konzentriert sich darauf, was eine Änderung bewirkt, anstatt nach bekanntermaßen schädlichen Dateien zu suchen. Deshalb reicht es nicht aus, dieselbe Technik unter anderen Dateinamen neu zu verpacken, um die Sicherheitsbarriere zu umgehen.
Die Erkennung auf Quellcodeebene ist der SecureChain-Mechanismus, der direkt die erste Schwachstelle angeht. Ein Neuaufbau aus dem Quellcode hilft nicht, wenn gerade der Quellcode selbst manipuliert wurde. Das war das Argument, das wir im Juni in Bezug auf die Herkunft vorgebracht haben, und diese Kampagne hat daran nichts geändert. Sie hat es vielmehr noch verdeutlicht, indem sie beide Fehlermodi an ein und demselben Nachmittag aufgezeigt hat.
Risikominderung ohne SecureChain
Falls Ihre Builds direkt aus dem öffentlichen Register abgerufen werden, wären dies die Kontrollmechanismen, die diese Kampagne eingeschränkt hätten – in der Reihenfolge ihrer Wirksamkeit.
Stellen Sie sicher, dass auf jedem Entwicklerrechner und jedem CI-Runner npm 12 oder höher installiert ist. Die preinstall Die Standardänderung ist der Unterschied zwischen einem manipulierten Tarball, der sich in node_modules und ein beschädigter Tarball, der ausgeführt wurde. Falls Sie noch kein Upgrade durchführen können, installieren Sie mit --ignore-scripts und die Pakete, die tatsächlich Build-Schritte erfordern, als benannte Ausnahmen behandeln.
Legen Sie eine Mindestwartezeit fest, damit Ihre Builds niemals eine Version installieren, sobald diese erscheint. Alle vier großen Paketmanager bieten diese Funktion mittlerweile standardmäßig an: npm verfügt über min-release-age Ab Version 11.10.0 verfügt Bun über minimumReleaseAge Ab Version 1.3.0 bieten sowohl pnpm als auch yarn entsprechende Funktionen für paketbezogene Ausschlüsse. Drei bis sieben Tage kosten Sie nur sehr wenig und hätten das gesamte vierstündige Zeitfenster dieser Kampagne abgedeckt. Wenn Sie aus diesem Beitrag nur eine Konfigurationsänderung mitnehmen, dann sollte es diese sein.
Überprüfen Sie npm-Token auf Schreibberechtigungen in Kombination mit einer Umgehung der Zwei-Faktor-Authentifizierung (2FA) – genau diese Kombination hat der Wurm ausgenutzt. Veröffentlichungstoken sollten nur von kurzer Dauer sein, auf die Pakete beschränkt sein, die sie benötigen, und eher an Automatisierungsprozesse als an Personen vergeben werden. Bevorzugen Sie vertrauensbasierte Veröffentlichungen, sofern der Workflow dies unterstützt, und beachten Sie dabei, dass sich aus dem OpenSearch-Fall ergibt, dass dadurch die Vertrauensgrenze lediglich auf Ihre Workflow-Definitionen verlagert wird, anstatt sie aufzuheben.
Behandeln Sie CI-Runner als Produktionssysteme, die mit vertraulichen Daten umgehen, da diese Nutzlast den Arbeitsspeicher des Runner-Prozesses ausgelesen hat. Beschränken Sie OIDC-Vertrauensrichtlinien auf bestimmte Repositorys und bestimmte Workflow-Dateien statt auf eine gesamte Organisation und verlangen Sie eine Überprüfung bei Änderungen unter .github/workflows.
Überprüfen Sie, welche Vorgänge Ihr Editor und Ihre KI-Codierungstools automatisch aus einem Repository ausführen. Die .vscode/tasks.json und .claude/settings.json Vector funktioniert, weil beim Öffnen eines Projekts die mitgelieferte Konfiguration ausgeführt wird. Behandeln Sie diese Dateien bei der Codeüberprüfung als ausführbaren Inhalt, denn genau das sind sie.
Erkennung
Durchsuche jeden Zweig jedes Repositorys – nicht nur die Standardzweige – nach den fünf Hook-Dateien: .vscode/tasks.json die eine Aufgabe „Umgebungskonfiguration“ enthält, .vscode/setup.mjs, .claude/setup.mjs, .claude/math_init.jsund .claude/settings.json mit einem SessionStart Hook. Suche nach Commits mit dem Titel chore: update config, insbesondere bei einer Mitautorzeile, in der [email protected].
Durchsuche Abhängigkeitsbäume und Paket-Caches nach den Dateinamen setup.mjs, math_init.js, Math_Symbol.js und router_runtime.js. JFrog hat den SHA-256-Hash der Nutzlast veröffentlicht, die es aus keyv 6.0.0 – verwenden Sie daher nach Möglichkeit diese Versionsangabe als Suchkriterium und nicht nur die Dateinamen.
Suchen Sie in den GitHub-Prüfprotokollen nach dem dependabot/github_actions/format/setup-formatter Zweig, Workflow-Läufe mit dem Namen codeql_analysis.yml oder „Run Copilot“, mit denen sich ein Artefakt schnell erstellen und löschen lässt, sowie jedes Artefakt mit dem Namen format-results. Suchen Sie nach Repositories, die unter den Konten Ihrer Organisation erstellt wurden und deren Beschreibungen dem Muster „Shai-Hulud: Here We Go Again“ entsprechen.
Auf der Netzwerkseite sollten Sie nach Verbindungen zu npm-cache.com, sowie für ausgehenden Datenverkehr zu öffentlichen Ethereum-RPC-Endpunkten aus einer Build-Infrastruktur, die eigentlich gar nicht mit einer Blockchain kommunizieren sollte. Die Nutzlast liest ihre aktuelle C2-Domain-Liste aus einem Ethereum-Mainnet-Vertrag aus, sodass beide als nützliche Erkennungsmerkmale dienen, keines davon jedoch eine verlässliche Sperre darstellt.
Checkliste zur Behebung des Shai-Hulud-npm-Angriffs, nach Priorität geordnet
- Stellen Sie fest, ob
preinstallSkripte überhaupt ausgeführt worden sein könnten. Überprüfen Sie die npm-Version auf jedem Rechner und jedem Runner, auf dem am oder nach dem 4. August 2026 Abhängigkeiten installiert wurden, und ob--ignore-scriptswar aktiv. Falls die Hooks nicht ausgeführt werden konnten, besteht Ihre verbleibende Arbeit eher in der Beseitigung von Abhängigkeitsproblemen als in der Reaktion auf Vorfälle. - Isolieren Sie die Umgebung, bevor Sie die Berechtigungen widerrufen. Sichern Sie zunächst die Tarballs, npm-Protokolle, CI-Protokolle, GitHub-Audit-Protokolle und Runner-Images. Angesichts des gemeldeten Löschverhaltens bei der Token-Widerrufung sollten Sie auf jedem Host, von dem Sie annehmen, dass dort die Payload ausgeführt wurde, vor der Rotation der Anmeldedaten eine Isolierung der Abläufe vornehmen.
- Legen Sie für jedes betroffene Paket die Lockfiles auf Versionen fest, die vor dem 4. August 2026 veröffentlicht wurden, und leeren Sie die Caches des Paketmanagers, damit die manipulierten Tarballs nicht lokal gespeichert bleiben.
- Widerrufen Sie zunächst die npm-Token, beginnend mit allen, die Schreibrechte und eine Umgehung der Zwei-Faktor-Authentifizierung ermöglichen, anschließend die persönlichen GitHub-Zugriffstoken und die Actions-Token.
- Drehen Sie alles, was der Collector lesen könnte – unter der Annahme, dass er es gelesen hat: Cloud-Anmeldedaten, Kubernetes-Dienstkontotoken, Vault-Inhalte, Datenbank-Anmeldedaten, SSH-Schlüssel, VPN-Profile, Stripe- und Slack-Token sowie API-Schlüssel für KI-Dienste.
- Durchsuche alle Zweige aller Repositorys nach den fünf Hook-Dateien und den Marker-Commits und entferne sie.
- Stellen Sie CI-Runner und Entwicklerumgebungen anhand sauberer Images neu auf. Das Löschen einzelner Dateien bedeutet nicht, dass der Rechner auch wirklich sauber ist.
- Prüfen Sie die Richtlinien für vertrauenswürdige npm-Anbieter und die OIDC-Vertrauensrichtlinien von GitHub und achten Sie dabei besonders auf Workflows zur automatisierten Veröffentlichung, da diese gezielt ins Visier genommen wurden.
- Erst dann sollten Sie sich der Prävention zuwenden: Mindestanforderungen für die Veröffentlichung, npm 12, Token-Scoping, Anforderungen an die Überprüfung von Workflows.
Warum das immer wieder funktioniert
Die Zuordnung ist noch ungeklärt. Von CyberScoop zitierte Forscher wiesen darauf hin, dass sie bislang noch keine eindeutigen Hinweise haben, die einen Zusammenhang mit TeamPCP belegen – dem Akteur, der Anfang 2026 mehr als tausend Pakete kompromittiert hatte –, obwohl diese Möglichkeit nicht ausgeschlossen ist. Mehrere Unternehmen meldeten dieselbe Payload und dasselbe Muster bei allen betroffenen Paketen, was eher auf einen einzigen Akteur oder eine eng koordinierte Gruppe hindeutet als auf Nachahmer.
Die Frage nach der Zuordnung ist weniger interessant als die strukturelle Frage. Dieselbe Technik funktioniert immer wieder, weil es sich nicht wirklich um eine Technik handelt, sondern um eine Beobachtung darüber, wie Paket-Ökosysteme aufgebaut sind: Jeder, der eine Version eines Pakets veröffentlichen kann, kann Code auf jedem Rechner ausführen, auf dem dieses Paket installiert ist. Das ist kein Fehler in npm. Genau dafür ist ein Lebenszyklus-Skript gedacht, und Tausende legitimer Pakete sind auf dieses Verhalten angewiesen.
Hinzu kommt, dass die Veröffentlichungsrechte bei Einzelpersonen liegen, dass diese Personen Token besitzen, dass sich die Token in Dateien auf Laptops befinden und dass die Nutzlast als Erstes nach diesen Dateien sucht. Die Verbreitung des Wurms ist keine außergewöhnliche Fähigkeit; es handelt sich um den üblichen Veröffentlichungsablauf, der jedoch nicht von einem Betreuer, sondern von Malware ausgeführt wird.
Im Juni lautete das Argument, dass eine Überprüfung der Herkunft auf „grün“ lediglich ein Anhaltspunkt bei der Vertrauensentscheidung sei und kein endgültiges Urteil darstelle. Im August ist das Argument enger gefasst und eher mechanischer Natur: Wenn die Version, auf die Ihr Build verweist, genau die ist, die ein Angreifer mit einem gestohlenen Token zuletzt hochgeladen hat, dann sind alle anderen Kontrollmaßnahmen, über die Sie verfügen, von einer Entscheidung abhängig, die Sie nicht selbst getroffen haben.
Treffen Sie diese Entscheidung also bewusst. Sehen Sie sich an, welche Versionen Ihre Builds am 4. August aufgelöst haben, und legen Sie dann vor der nächsten Welle – denn die wird es geben – eine Mindestdauer für die Veröffentlichung fest. Wenn Sie es vorziehen, dass die Versionen, die Ihre Builds auflösen, aus einem Katalog stammen, der von jemandem neu erstellt und überprüft wird, anstatt von demjenigen, der über ein Veröffentlichungstoken verfügt, sprechen Sie mit uns über SecureChain für npm.
FAQ
Ist das dasselbe wie die Shai-Hulud-Kampagne vom September 2025?
Es handelt sich um dieselbe Abstammungslinie – und sie bezeichnet sich auch selbst so –, aber nicht um denselben Vorfall. Der Shai-Hulud-NPM-Angriff vom August 2026 erfolgte über keyv und cacheable anstatt der zuvor betroffenen Pakete, und CyberScoop beschreibt es als eine Variante von „Mini Shai-Hulud“. Den von Wiz ermittelten Zahlen zur Verbreitung in verschiedenen Umgebungen zufolge hat es eine deutlich größere Reichweite erreicht als seine Vorgänger.
Das GitHub-Repository des Pakets sieht einwandfrei aus. Bedeutet das, dass die von mir installierte Version ebenfalls einwandfrei ist?
Nein, und genau dieses Detail wird am ehesten übersehen. Bei den mehreren hundert Sekundärpaketen hat der Angreifer das Quell-Repository überhaupt nicht berührt. Der Schadcode befand sich ausschließlich in dem bei npm veröffentlichten Tarball. Ein sauberes Repository sagt nichts darüber aus, was Ihr Paketmanager tatsächlich heruntergeladen hat. Überprüfen Sie die Version, die Ihre Lockfile aufgelöst hat, nicht den Quellcode.
Bedeutet eine gültige Signatur oder Herkunftsbescheinigung, dass ein Paket sicher ist?
Nein. Im Fall von OpenSearch hat diese Kampagne über Fulcio und Rekor ein echtes Sigstore-Bundle für ein bösartiges Tarball-Archiv generiert, das über einen vertrauenswürdigen Workflow veröffentlicht wurde. Die Provenienz bestimmt die Herkunft. Sie bewertet den Inhalt nicht.
Wir nutzen ein privates Repository, das als Proxy für npm fungiert. Sind wir damit geschützt?
Nur wenn er mehr tut, als Artefakte einfach weiterzuleiten. Ein Caching-Proxy speichert die manipulierte Version gerne im Cache und stellt sie bereit – in der Regel schneller, als es der Upstream tun würde. Entscheidend ist, ob irgendetwas die durchgeleiteten Daten überprüft, neu erstellt oder verzögert.
Wir führen bei jedem Build einen Schwachstellenscanner durch. Warum wurde das nicht erkannt?
Es gab keine bekannte Sicherheitslücke, die aufgedeckt werden konnte. Scanner gleichen Ihren Abhängigkeitsbaum mit CVE-Datenbanken ab, und am 4. August waren die manipulierten Versionen bereits mehrere Stunden alt, ohne dass ein entsprechender Sicherheitshinweis vorlag. Das Scannen nach bekannten Sicherheitslücken und die Erkennung von Schadcode sind unterschiedliche Probleme, die unterschiedliche Tools erfordern.
Was hätte SecureChain in diesem Fall getan?
Zwei unterschiedliche Aspekte bei den beiden Zugriffspfaden. Bei den mehreren hundert Paketen, die durch die Neuveröffentlichung von Tarballs kompromittiert wurden, befindet sich die manipulierte Version nicht in dem Pfad, aus dem Ihr Build bezieht, da SecureChain die von TuxCare aus dem Quellcode erstellte Version bereitstellt, anstatt die zuletzt vom Upstream veröffentlichte Version weiterzuleiten. Für die anfängliche keyv und cacheable Kompromiss: Wenn der Code zuerst in das Repository aufgenommen wurde, liest der Schadcode-Detektor beim Onboarding den Versionsvergleich und hält die Veröffentlichung zurück, sodass die manipulierte Version niemals in den Katalog gelangt. Beides gilt für die gesamte SecureChain Katalog, für jede darin enthaltene Komponente.

