Der keyv-npm-Angriff: Preinstall-Malware, vertrauenswürdige Provenance und IDE-Hooks
4. August 2026
0 Min. LesezeitAngreifer kompromittierten am 4. August 2026 den Release-Prozess von keyv und verwandten npm-Paketen. Die bösartigen Releases fügen einen preinstall-Hook hinzu, der vor dem Start des Anwendungscodes einen verschleierten Loader ausführt und anschließend eine wesentlich umfangreichere Payload der zweiten Stufe startet.
Dies ist ein aktiver Software-Supply-Chain-Vorfall, kein Proof of Concept. Snyk Security Research hat die veröffentlichten Tarballs unabhängig heruntergeladen und verglichen, ohne sie zu installieren, alle von npm für den Maintainer jaredwray zurückgegebenen Pakete aufgelistet und 11 bösartige Releases mit denselben beiden Payload-Dateien identifiziert. Um 11:16 UTC waren acht dieser Releases noch mit dem Tag latest versehen.
Kurzfassung
Vorfall: Eingebetteter bösartiger Code in legitimen npm-Paketen
Primäres Paket:
keyv@6.0.0Von Snyk gefundene betroffene Releases: 11 in Paketen aus dem Umfeld von
keyv,cacheableundectoAusführung:
"preinstall": "node setup.mjs"Payload:
setup.mjslädt eine 727.680 Byte große Payload der zweiten Stufe namensMath_Symbol.jsBeobachteter Status um 11:16 UTC: Acht bösartige Releases trugen weiterhin den Tag
latest. Drei waren entfernt worden.Advisory:
SNYK-JS-KEYV-18515941CVE/GHSA: Zum Zeitpunkt der Recherche war keine CVE- oder GHSA-ID vergeben
Operative Schwere: Kritisch, da die Installation die Ausführung von angreifergesteuertem Code mit den Berechtigungen eines Entwicklers oder CI-Runners ermöglicht
Behebung: Fixieren Sie die Version oder führen Sie ein Downgrade auf ein zuletzt als sicher bekanntes Release durch. Es war kein bereinigtes Nachfolge-Release von
keyv@6.0.0veröffentlicht worden.Sofortmaßnahme: Installieren Sie die betroffenen Versionen nicht. Falls eine davon ausgeführt wurde, isolieren Sie den Host, suchen und deaktivieren Sie Persistenzmechanismen und rotieren Sie offengelegte Zugangsdaten von einem sauberen System aus.
Schweregrad und Advisory-Status
Snyk veröffentlichte SNYK-JS-KEYV-18515941, während dieser Entwurf erstellt wurde. Das Advisory stuft keyv@6.0.0 als eingebetteten bösartigen Code gemäß CWE-506 ein.
Während unserer Recherche war weder eine CVE-ID vergeben noch ein GitHub-Advisory-Eintrag angelegt worden. Bei der Installation wird angreifergesteuerter Code ohne zusätzliche Berechtigungen oder Interaktion mit der Anwendung ausgeführt. Dabei nutzt er die Berechtigungen und Zugangsdaten, die dem Entwickler- oder CI-Prozess zur Verfügung stehen.
Was Snyk unabhängig bestätigt hat
Wir fragten den npm-Registry-Suchendpunkt nach Paketen ab, die von jaredwray gepflegt werden. Der Endpunkt gab 61 Paketnamen zurück. Für jeden Namen riefen wir das Registry-Manifest ab, untersuchten alle am 4. August veröffentlichten Versionen und prüften ihre Lifecycle-Skripte und Tarball-Metadaten.
Bei der Prüfung wurden die folgenden bösartigen Releases gefunden. Zugleich bestätigte sich, dass die übrigen Pakete im Bereich @keyv nicht kompromittiert waren:
keyv@6.0.0, veröffentlicht um 09:35:00 UTC@cacheable/net@2.1.1, veröffentlicht um 10:09:44 UTC@cacheable/node-cache@3.1.2, veröffentlicht um 10:10:34 UTCcacheable@2.5.1, veröffentlicht um 10:10:44 UTCflat-cache@6.1.24, veröffentlicht um 10:10:55 UTC und anschließend entfernt@cacheable/memory@2.2.1, veröffentlicht um 10:11:29 UTCcacheable-request@13.0.20, veröffentlicht um 10:11:24 UTC und anschließend entferntfile-entry-cache@11.1.6, veröffentlicht um 10:13:02 UTC@cacheable/utils@2.5.1, veröffentlicht um 10:14:21 UTCcache-manager@7.2.10, veröffentlicht um 10:14:41 UTC und anschließend entferntecto@5.0.1, veröffentlicht um 10:28:01 UTC
Der letzte Eintrag ist wichtig, um den Umfang des Vorfalls einzugrenzen. ecto@5.0.1 erschien nach den ersten öffentlichen Warnungen; die Dateien setup.mjs und Math_Symbol.js sind byteidentisch mit den Dateien in keyv@6.0.0. Frühe Paketlisten, in denen ecto fehlt, sind unvollständig.
Bei unserer Momentaufnahme um 11:16 UTC hatte npm flat-cache@6.1.24, cacheable-request@13.0.20 und cache-manager@7.2.10 entfernt und ihre latest-Tags auf 6.1.23, 13.0.19 und 7.2.9 zurückgesetzt. Die anderen acht betroffenen Releases waren weiterhin verfügbar und mit latest markiert. Der Registry-Status kann sich während eines aktiven Vorfalls schnell ändern. Deshalb müssen Sie auch private Mirrors und Lockfiles in die Untersuchung einbeziehen, selbst wenn npm eine Version entfernt hat.
Der veröffentlichte Tarball unterscheidet sich an drei Stellen
Wir luden keyv@6.0.0 und den Release Candidate keyv@6.0.0-rc.1 direkt aus der Registry herunter und verglichen jede Datei anhand ihres SHA-256-Hashes. Wir führten weder eine Paketinstallation durch noch führten wir eine der beiden Payloads aus.
Nur drei Pfade unterscheiden sich:
package.jsonwurde von Version6.0.0-rc.1auf6.0.0geändert. Die zwei Payload-Dateien wurden zur Liste der veröffentlichten Dateien hinzugefügt und daspreinstall-Skript ergänzt.setup.mjswurde mit einer Größe von 29.918 Byte hinzugefügt.Math_Symbol.jswurde mit einer Größe von 727.680 Byte hinzugefügt.
Jede Datei unter dist/ ist im Release Candidate und im kompromittierten stabilen Release byteidentisch. Die Bibliothek funktioniert nach der Installation weiterhin normal, während der Lifecycle-Hook separat ausgeführt wird. Dieser kleine Diff ist ein nützlicher Hinweis für die Erkennung und zugleich eine wirksame Verschleierungstechnik.
Die Änderung am Manifest ist direkt:
Das Registry-Manifest von keyv@6.0.0 weist den folgenden Integritätswert für den Tarball aus:
Unsere unabhängig ermittelten Hashes lauten:
Anschließend wiederholten wir die Überprüfung der Payload-Hashes für alle betroffenen Releases, die während unserer ersten Analyse abrufbar waren. Alle neun zu diesem Zeitpunkt verfügbaren Tarballs enthielten dieselbe 29.918 Byte große Datei setup.mjs und dieselbe 727.680 Byte große Datei Math_Symbol.js – mit exakt den oben genannten Hashes. npm entfernte später eine dieser Versionen. Verwenden Sie zur Erkennung Hashes und Lifecycle-Verhalten, statt sich auf einen einzelnen Paketnamen zu verlassen.
So wird die Malware ausgeführt
npm führt preinstall automatisch aus, wenn Abhängigkeiten installiert werden. Entwickler müssen dafür weder keyv importieren noch eine Anwendung starten oder eine anfällige API aufrufen. Es reicht aus, das betroffene Paket aufzulösen und zu installieren.
Die statische Analyse von setup.mjs zeigt Plattformprüfungen für Linux, macOS und Windows, die Verwendung von child_process.execFileSync, Dateisystemoperationen, HTTPS-Zugriffe und die Verarbeitung der Bun-Laufzeit. Der weniger stark verschleierte Loader unter .claude/setup.mjs nennt Bun-Version 1.3.13 und den Dateinamen der zweiten Stufe: math_init.js. Fehlt Bun, kann der Loader eine passende Bun-Version von GitHub herunterladen, die umfangreichere Payload ausführen und temporäre Laufzeitdateien entfernen.
Eine unabhängige Malware-Analyse, die den Vorfallberichten beigefügt war, deutet darauf hin, dass die verschlüsselte Payload der zweiten Stufe GitHub- und npm-Tokens, Cloud-Zugangsdaten, private Schlüssel, Datenbankverbindungszeichenfolgen, Vault-Tokens, Kubernetes-Service-Account-Tokens und den Arbeitsspeicher von GitHub-Actions-Runners ins Visier nimmt. Laut der Analyse enthält sie außerdem den Persistenzmechanismus gh-token-monitor, der ein gestohlenes GitHub-Token überwacht und einen bereitgestellten Handler ausführt, sobald das Token nicht mehr funktioniert.
Wir haben Math_Symbol.js weder ausgeführt noch unabhängig entschlüsselt. Die Angaben zu den Fähigkeiten der zweiten Stufe sollten daher dieser Analyse zugeschrieben bleiben. Die operativen Empfehlungen stimmen mit Snyks früherer Analyse desselben Persistenzmusters gh-token-monitor überein: Eindämmen und deaktivieren Sie den Monitor, bevor Sie Tokens widerrufen.
Ein zweiter Ausführungspfad nimmt Entwicklungstools ins Visier
Der npm-Lifecycle-Hook ist nur ein möglicher Einstiegspunkt. Ein GitHub-API-Eintrag zum Commit d8c850c7 zeigt, dass dem keyv-Repository fünf Dateien hinzugefügt wurden:
.claude/settings.json.claude/setup.mjs.claude/math_init.js.vscode/tasks.json.vscode/setup.mjs
Die Claude-Konfiguration registriert einen SessionStart-Befehl, der .vscode/setup.mjs aufruft. Die VS-Code-Aufgabe verwendet runOn: "folderOpen" und ruft .claude/setup.mjs auf. Diese Dateien schaffen einen zusätzlichen Ausführungspfad, wenn ein Entwickler oder Coding-Agent der projektspezifischen Konfiguration vertraut und sie aktiviert. Je nach Workspace-Vertrauen und Benutzereinstellungen fragt VS Code möglicherweise nach, bevor automatische Aufgaben zugelassen werden. Das Öffnen eines ausgecheckten Repositorys ist daher eine mögliche Gefährdung, aber kein Beweis dafür, dass Code ausgeführt wurde.
GitHub hat den Commit kryptografisch verifiziert; als Urheber ist github-actions[bot] angegeben. Ein verifiziertes Badge beweist, dass GitHub das Commit-Objekt signiert hat. Es belegt nicht, dass der Projekt-Maintainer die Änderung autorisiert hat. Die Belege sprechen für die Kompromittierung eines Kontos, einer Zugangsdaten, einer Sitzung oder eines Release-Prozesses. Sie identifizieren nicht die Person, die dahintersteckt. Der Maintainer sollte als Opfer des Vorfalls betrachtet werden.
Eine gültige Provenance signierte das bösartige Release
Das npm-Manifest weist GitHub Actions als vertrauenswürdigen Publisher für keyv@6.0.0 aus und verweist auf eine npm-Attestation für das Release. Der bösartige Quellcode war im markierten Repository-Stand enthalten, sodass der legitime Workflow das bösartige Artefakt erstellte und attestierte.
Der Patch des Release-Commits fügte außerdem einen Test hinzu, der setup.mjs über execFileSync ausführte. Ein späterer Commit entfernte nur diesen Test. Beim Ausführen der Release-Testsuite hätte die Malware somit vor der Veröffentlichung in der CI-Umgebung ausgeführt werden können.
Provenance bleibt ein wertvoller Nachweis für die Herkunft eines Builds. Dieser Vorfall zeigt jedoch ihre Grenzen: Provenance kann einen Build zuverlässig attestieren, dessen Quellcode oder Workflow-Kontext bereits kompromittiert wurde.
Auswirkungen und wahrscheinliche Reichweite
Die am stärksten betroffenen Pakete verzeichnen sehr hohe Installationszahlen. npm registrierte vom 5. Juli bis zum 3. August 619.682.667 Downloads für keyv, 579.751.309 für flat-cache und 571.240.025 für file-entry-cache.
Diese Zahlen überschneiden sich stark, weil die Pakete voneinander abhängen und in denselben Toolchains vorkommen. Sie zeigen die Reichweite im Ökosystem, nicht die Anzahl kompromittierter Hosts. Zudem war jede einzelne bösartige Version deutlich kürzer als einen Monat verfügbar.
Snyk beobachtet eine große potenzielle Reichweite in den überwachten Projekten. Auch die transitive Nutzung ist relevant, da flat-cache und file-entry-cache häufig über Entwicklungstools wie ESLint eingebunden werden. Besonders attraktive Ziele sind Entwickler-Laptops und CI-Runners, da dort oft GitHub-, npm-, Cloud-, Signierungs- und Deployment-Zugangsdaten gespeichert sind.
Zum Zeitpunkt der Veröffentlichung gibt es keine verifizierte öffentliche Zahl erfolgreicher Ausführungen der Payload der zweiten Stufe oder exfiltrierter Zugangsdaten. Die Pakete wurden aktiv in der produktiven npm-Registry veröffentlicht; in unserer Momentaufnahme waren acht weiterhin mit latest markiert. Das bestätigt eine tatsächliche Verbreitung und keinen Labor-Exploit. Snyks Advisory stuft den Reifegrad des Exploits als „Attacked“ ein, veröffentlicht jedoch keine Zahl der Betroffenen.
So erkennen Sie eine mögliche Gefährdung
Prüfen Sie zunächst den aufgelösten Abhängigkeitsbaum einschließlich transitiver Abhängigkeiten:
Durchsuchen Sie Lockfiles, da eine betroffene Version weiterhin fixiert sein kann, nachdem npm ein Dist-Tag geändert hat:
Prüfen Sie installierte Manifeste auf den exakten Hook, ohne Paketcode auszuführen:
Suchen Sie nach der Payload und Hinweisen auf Persistenz:
Untersuchen Sie außerdem Repositorys, auf die Sie mit offengelegten GitHub-Zugangsdaten zugreifen können, auf unerwartete Dateien wie .claude/settings.json, .vscode/tasks.json, Workflow-Dateien mit toJSON(secrets) und neu erstellte GitHub-Actions-Artefakte.
Snyk-Kunden können das neue Advisory zu keyv@6.0.0 nutzen. Führen Sie Abhängigkeitstests erneut aus und überwachen Sie Ihre Projekte, während die Erkenntnisse zum Vorfall aktualisiert werden:
Die Lektion von Snyk Learn zu kompromittierten legitimen Paketen bietet zusätzlichen Kontext dazu, wie sich die Integrität von Abhängigkeiten und Registry-Kontrollen in normale Entwicklungs-Workflows integrieren lassen.
Behebung
Wenn ein betroffenes Paket installiert wurde
Gehen Sie davon aus, dass der Rechner oder Runner möglicherweise kompromittiert ist – auch wenn node_modules bereits gelöscht wurde.
Isolieren Sie den Host vom regulären Netzwerkzugriff. Sichern Sie für die Untersuchung Protokolle, Prozessdaten, npm-Logs, CI-Job-Ausgaben und Zeitstempel des Dateisystems.
Suchen Sie nach
gh-token-monitor-Persistenzmechanismen, bevor Sie GitHub-Zugangsdaten widerrufen. Prüfen Sie~/.local/bin/gh-token-monitor.sh,~/.config/gh-token-monitor/,~/.config/systemd/user/gh-token-monitor.serviceund~/Library/LaunchAgents/com.user.gh-token-monitor.plist.Deaktivieren Sie alle gefundenen Persistenzmechanismen. Stimmen Sie deren Entfernung mit dem Incident-Response-Team ab und sichern Sie eine forensische Kopie. Der Widerruf kann für den Monitor sichtbar sein.
Rotieren Sie Zugangsdaten von einem nachweislich sauberen System aus. Berücksichtigen Sie GitHub-PATs und App-Tokens, npm-Tokens, AWS, GCP, Azure, Vault, Kubernetes, Datenbankzugangsdaten, private Schlüssel sowie alle Geheimnisse, auf die betroffene CI-Jobs zugreifen konnten.
Prüfen Sie die Audit-Logs von Konten und Cloud-Umgebungen. Achten Sie auf unerwartete npm-Veröffentlichungen, Repository-Erstellungen, Workflow-Änderungen, Actions-Artefakte, Cloud-API-Aufrufe und die Verwendung von Tokens von unbekannten Standorten.
Entfernen Sie betroffene Artefakte aus privaten Registries und Caches. Durch das Entfernen aus npm werden keine Kopien gelöscht, die bereits in einem internen Proxy oder Entwickler-Cache gespeichert sind.
Legen Sie bekannte saubere Versionen fest, bevor Sie neu installieren
Die folgenden früheren Releases hatten bei unserer Prüfung in ihren Registry-Manifesten keinen Install-Lifecycle-Hook:
keyv@5.6.0 ist in unserem Snapshot die neueste stabile, saubere Version der 5.x-Reihe. Ein Wechsel von keyv@6.0.0 zurück auf 5.x kann Codeänderungen erfordern. 6.0.0-rc.1 hatte ein byte-identisches dist/-Ergebnis und keinen Lifecycle-Hook. Produktionsteams sollten jedoch ein etabliertes stabiles Release bevorzugen, sofern sie den Release Candidate nicht ausdrücklich validiert haben.
Erstellen Sie nach dem Hinzufügen von Overrides die Lockdatei neu, ohne Lifecycle-Skripte auszuführen:
Das Deaktivieren von Lifecycle-Skripten schränkt diesen Ausführungspfad ein. Einige legitime Pakete benötigen Install-Skripte. Teams sollten daher eine eng gefasste Zulassungsliste pflegen, statt Skripte global zu aktivieren. Snyks npm-Sicherheits-Best Practices erläutern deterministische Installationen, Skriptkontrollen und die Paketprüfung ausführlicher.
Zeitlicher Ablauf des Vorfalls
Alle folgenden Zeitangaben sind UTC und beziehen sich auf den 4. August 2026.
09:02 bis 09:17: Commit
ee2681a9bereitetkeyv@6.0.0vor und fügt den Lifecycle-Hook, Payload-Dateien und einen Test hinzu, der den Loader ausführt. GitHub verzeichnet eine Autorzeit von 09:02 und eine Committer-Zeit von 09:17.09:04: Der verifizierte Commit
d8c850c7fügt Ausführungs-Hooks für Claude und VS Code hinzu.09:23: Commit
f97eabcdentfernt den Preinstall-Test.09:30 bis 09:32: Mehrere Pakete der Version 6 aus der Gruppe
@keyv/*werden ohne den schädlichen Hook veröffentlicht.09:35: npm veröffentlicht
keyv@6.0.0mit dem schädlichen Hook.09:51: Commit
1f79edd8fügt die Payload-Dateien in allen Workspaces von@keyv/*hinzu und schafft damit ein Risiko für nachfolgende Releases.09:49 bis 09:51: Die GitHub-Issues
#2044,#2045und#2046melden den Vorfall. Die Issue-API lieferte später410 Gonezurück.10:09 bis 10:14: Die schädlichen Releases der Cacheable-Familie werden veröffentlicht.
10:18 und 10:20: Der Sicherheitsforscher Charlie Eriksen veröffentlicht die beiden bereitgestellten öffentlichen Warnungen.
10:28:
ecto@5.0.1wird mit derselben Payload veröffentlicht. Damit umfasst die Liste der mit dem Maintainer verknüpften Pakete nun 11 Einträge.10:39: Die npm-Registry-Metadaten ändern sich, nachdem
cacheable-request@13.0.20entfernt wurde.10:42: Die npm-Registry-Metadaten ändern sich, nachdem
flat-cache@6.1.24entfernt wurde.11:11: Die npm-Registry-Metadaten ändern sich, nachdem
cache-manager@7.2.10entfernt wurde.11:16: Der Registry-Snapshot von Snyk zeigt weiterhin acht schädliche Releases mit dem
latest-Tag.Während der Erstellung des Entwurfs: Snyk veröffentlicht
SNYK-JS-KEYV-18515941und rund 70 weitere Hinweise.
Dieser Zeitablauf bezieht sich auf einen laufenden Vorfall. Prüfen Sie npm-Manifeste, dist-tags und Snyk-Hinweise unmittelbar vor der Veröffentlichung erneut.
On-Demand-Webinar
OpenAI bewertete die eigenen Hausaufgaben – und drang anschließend in die Produktionsumgebung ein
Sehen Sie sich die Aufzeichnung des Webinars an und erfahren Sie, warum Selbstvalidierung strukturell scheitert, warum ein Multi-Modell-Stack das Problem verschärft und wie unabhängige Validierung in der Praxis aussieht. Nehmen Sie einen Leitfaden mit, um alle KI-Assets in Ihrer Umgebung zu verwalten – unabhängig davon, welches Labor sie entwickelt hat.
