Für Entwicklerteams ist die wichtigste Konsequenz: Wer eine betroffene Version installiert hat, sollte nicht nur das Paket austauschen. Der gesamte Rechner oder CI/CD-Runner muss als potenziell kompromittiert behandelt werden.
Gegen 09:00 Uhr UTC am 4. August 2026 erlangten Angreifer Kontrolle über das GitHub-Konto von Jared Wray (jaredwray) . Mit diesem Zugriff änderten sie direkt den main-Branch des keyv-Repositorys und veröffentlichten anschließend neue Versionen aus der keyv- und cacheable-Paketfamilie .
Die erste Infektionswelle umfasste elf Pakete aus beiden Namensräumen. Dazu gehörten unter anderem keyv, cacheable-request, cache-manager, @cacheable/utils, flat-cache und file-entry-cache . Sicherheitsunternehmen wie Aikido Security, StepSecurity, Socket und Chainguard bestätigten die Kompromittierung unabhängig voneinander .
Die manipulierten Pakete wiesen ein einheitliches Muster auf: Sie enthielten zwei zusätzliche Dateien – setup.mjs und Math_Symbol.js – sowie einen geänderten Eintrag in der package.json:
"preinstall": "node setup.mjs"
Wurde eine betroffene Version mit npm install installiert, lief setup.mjs automatisch als sogenannter Preinstall-Hook, also noch vor dem Abschluss der Installation. Das Skript lud eine legitime Binärdatei der JavaScript-Laufzeitumgebung Bun aus den GitHub-Releases herunter und startete damit die stark verschleierte zweite Schadstufe Math_Symbol.js, die etwa 710 bis 728 KB groß war .
Microsoft Threat Intelligence ordnete die Payload einer Mini-Shai-Hulud-Variante zu . Sie zielte auf zahlreiche Geheimnisse aus Entwicklerrechnern und Build-Umgebungen, darunter :
Der Angriff blieb nicht auf die ursprünglich kompromittierten Pakete beschränkt. Nachdem der Wurm npm-Veröffentlichungstoken und GitHub-PATs aus einer infizierten Umgebung ausgelesen hatte, nutzte er diese Berechtigungen, um weitere Versionen zu veröffentlichen – auch von Paketen anderer, unabhängiger Maintainer .
Die Zahl der betroffenen Pakete stieg entsprechend schnell:
Der Wurm übersprang dabei Namespace-Grenzen. Er blieb also nicht in der ursprünglichen keyv- und cacheable-Familie, sondern erreichte auch Pakete von Organisationen wie Deliveroo, Ornikar, OneReach, Picsart, Qlik und ServiceTitan .
Die erbeuteten Zugangsdaten wurden an ein vom Angreifer kontrolliertes GitHub-Repository übertragen. Der Wurm konnte dafür entweder ein neues Repository anlegen oder ein dediziertes Exfiltrations-Repository verwenden . Die Payload enthielt außerdem mehrere redundante Übertragungswege, sodass die Kampagne nicht vom Ausfall eines einzelnen Kanals abhängig war .
Sicherheitsforscher empfahlen, betroffene Umgebungen nicht mit einer einfachen Dateilöschung zu bereinigen. Die wichtigsten Schritte sind:
Betroffene Pakete sollten unmittelbar auf bekannte, saubere Versionen zurückgesetzt oder ersetzt werden. Mit npm-, Yarn- oder pnpm-Overrides – beispielsweise über den Eintrag overrides in der package.json – lässt sich verhindern, dass eine manipulierte Version versehentlich erneut installiert wird .
Zusätzlich müssen die Lockfiles geprüft werden:
package-lock.jsonyarn.lockpnpm-lock.yamlDabei sind auch indirekte, transitive Abhängigkeiten zu berücksichtigen .
Wurde auf einem Rechner oder CI/CD-Runner eine betroffene Version mit npm install ausgeführt, reicht es nicht aus, nur die schädlichen Dateien zu löschen . Alle Geheimnisse, die in dieser Umgebung vorhanden oder erreichbar waren, sollten als offengelegt gelten.
Die folgenden Zugangsdaten sollten widerrufen und neu erstellt werden :
Ein wichtiger Sonderfall: Die Malware konnte offenbar GitHub-Workflow-Watcher einrichten, die neu erzeugte Token unmittelbar wieder auslesen oder offenlegen konnten . Daher sollten solche Überwachungs- und Revokierungsmechanismen zuerst deaktiviert oder entfernt werden. Erst danach sollten die Zugangsdaten rotiert werden .
npm-, pnpm- und Yarn-Caches müssen sowohl auf Entwicklerrechnern als auch auf CI/CD-Runnern geleert werden. Dasselbe gilt für Docker-Build-Caches . Anschließend sollten Artefakte vollständig neu gebaut werden, damit manipulierte Abhängigkeiten nicht in Cache-Schichten oder Docker-Layern erhalten bleiben .
Teams sollten nach neu angelegten Repositorys, nicht autorisierten Workflows und verdächtigen Commits suchen . Auch mögliche Persistenzmechanismen wie .claude/settings.json oder .vscode/tasks.json sollten kontrolliert werden .
Der Vorfall zeigt, wie schnell ein einzelnes kompromittiertes Maintainer-Konto eine Kaskade im JavaScript-Ökosystem auslösen kann. Der Angreifer benötigte keinen direkten Zugriff auf jedes einzelne Zielpaket: Gestohlene Token reichten aus, um die Schadsoftware mit neuen Veröffentlichungen weiterzutragen.
Die Kombination aus einem legitimen Bun-Download, einem automatisch ausgeführten preinstall-Skript, der systematischen Ernte von Entwickler- und Cloud-Geheimnissen sowie mehreren Exfiltrationskanälen machte den Angriff besonders widerstandsfähig .
Für Entwicklungs- und Sicherheitsteams ergeben sich daraus klare Lehren: Abhängigkeiten sollten möglichst exakt festgesetzt, Installationsskripte wo immer möglich eingeschränkt, ungewöhnliche GitHub-Aktivitäten überwacht und Notfallpläne für kompromittierte Software-Lieferketten regelmäßig geprobt werden.