TanStack-npm-Pakete im Mini-Shai-Hulud-Supply-Chain-Angriff kompromittiert
11. Mai 2026
0 Min. LesezeitTanStack-npm-Pakete kompromittiert: Einblicke in den Mini-Shai-Hulud-Supply-Chain-Angriff
Am 11. Mai 2026 zwischen 19:20 und 19:26 Uhr UTC wurden 84 schädliche npm-Paketartefakte in 42 Paketen im Namespace @tanstack veröffentlicht. Die Pakete wurden nicht von einem Angreifer veröffentlicht, der Zugangsdaten gestohlen hatte, sondern von der legitimen Release-Pipeline von TanStack – mit deren vertrauenswürdiger OIDC-Identität, nachdem vom Angreifer kontrollierter Code den Runner mitten im Workflow übernommen hatte. Innerhalb weniger Stunden verbreiteten sich die schädlichen Versionen zu Mistral AI, UiPath und Dutzenden weiteren Maintainer-Teams. Allein @tanstack/react-router wird wöchentlich über 12,7 Millionen Mal heruntergeladen (npm API).
StepSecurity schreibt den Vorfall der als TeamPCP bekannten Bedrohungsgruppe zu. Zudem handelt es sich um den ersten dokumentierten Fall eines schädlichen npm-Pakets mit gültiger SLSA-Provenienz. SLSA-Provenienz ist ein von Sigstore generiertes kryptografisches Zertifikat, das bestätigen soll, dass ein Paket aus einer vertrauenswürdigen Quelle erstellt wurde. Der Wurm konnte diese Zertifikate erzeugen, weil er die legitime Build-Pipeline selbst übernahm; Sigstore verifizierte den Build-Prozess korrekt. SLSA garantiert jedoch nicht, dass der erstellte Code sicher war.
Wenn Ihr Team am 11. Mai eine betroffene @tanstack/*-Version installiert hat, sollten Sie die Installationsumgebung als kompromittiert behandeln und alle Geheimnisse rotieren, auf die von diesem Host aus zugegriffen werden konnte. Lesen Sie weiter für die vollständige Paketliste, die technische Analyse und eine Schritt-für-Schritt-Anleitung zur Behebung.
CVE: CVE-2026-45321 | GHSA: GHSA-g7cv-rxg3-hmpx | Schweregrad: Kritisch
Welle vier: Hintergrund der Kampagne
Der TanStack-Angriff ist kein Einzelfall. Er ist die jüngste Welle einer Reihe von npm-Supply-Chain-Angriffen, bei denen die Shai-Hulud-Wurm-Toolchain zum Einsatz kommt. TeamPCP, dem StepSecurity diesen Angriff zuschreibt, ist auch für die Kompromittierung des Trivy-Scanners von Aqua Security (März 2026) und des Bitwarden-CLI-npm-Pakets (April 2026) verantwortlich. Bei den früheren Shai-Hulud-Wellen (September und November 2025) kam dieselbe Wurm-Toolchain zum Einsatz; sie wurden jedoch nicht TeamPCP zugeschrieben.
Welle | Datum | Umfang | Wichtige Eskalation |
|---|---|---|---|
14.–16. Sep. 2025 | Über 500 Pakete, über 700 Repos | Erster sich selbst verbreitender npm-Wurm; TruffleHog zum Aufspüren von Geheimnissen | |
21.–23. Nov. 2025 | 492 Pakete, 132 Mio. monatliche Downloads, über 25.000 Repos |
| |
29. Apr. 2026 | Erste Persistenz über einen KI-Coding-Agenten ( | ||
11. Mai 2026 | 373 schädliche Versionen, 169 Pakete | Erster npm-Wurm mit gültigen SLSA-Build-Level-3-Attestierungen; Session-P2P-C2 |
Jede Welle baut auf der technischen Raffinesse der vorherigen auf. Welle vier ist nicht wegen ihres Umfangs bemerkenswert (Welle 2 war größer), sondern wegen ihrer Leistung: Sie veröffentlichte schädliche Pakete, die sich anhand ihrer Provenienzattestierung nicht von legitimen Paketen unterscheiden ließen – eine Eigenschaft, die bei keinem früheren Supply-Chain-Angriff nachgewiesen worden war.
TeamPCP bekannte sich öffentlich zu dem Angriff. Die Gruppe ist auch unter den Aliasnamen DeadCatx3, PCPcat, ShellForce und CipherForce bekannt. Unit 42 hat die von der Gruppe angekündigte Partnerschaft mit der Vect-Ransomware-Gruppe dokumentiert, basierend auf einer Ankündigung auf BreachForums.
CISA veröffentlichte Warnungen sowohl zur ursprünglichen Welle vom September 2025 als auch zur Kompromittierung von tj-actions/changed-files (März 2025), bei der erstmals die OIDC-Token-Auslesetechnik dokumentiert wurde, die bei diesem Angriff erneut zum Einsatz kam.
Was betroffen war
Die TanStack-Router-Familie war der ursprüngliche Angriffsvektor. Durch den Mechanismus zur Selbstverbreitung des Wurms weitete sich der Schadensradius jedoch rasch aus.
TanStack-Pakete (42 Pakete, 84 Versionen – zwei pro Paket):
Paket | Kompromittierte Versionen |
|---|---|
1.169.5, 1.169.8 | |
1.169.5, 1.169.8 | |
1.169.5, 1.169.8 | |
1.169.5, 1.169.8 | |
1.167.68, 1.167.71 | |
1.167.38, 1.167.41 |
Die vollständige Liste der 42 Pakete finden Sie in GHSA-g7cv-rxg3-hmpx und in der Snyk-Sicherheitsdatenbank. Nachweislich nicht betroffene Familien: @tanstack/query*, @tanstack/table*, @tanstack/form*, @tanstack/virtual*, @tanstack/store.
Sekundär betroffene Pakete (durch den Wurm verbreitet):
Namespace | Beispielpakete |
|---|---|
| |
| Über 40 Pakete im UiPath-Namespace |
|
|
| 19 Pakete mit Luftfahrtdaten |
Verschiedene |
|
Bis zum Ende des Tages waren mindestens 170 betroffene Pakete in der Snyk-Sicherheitsdatenbank dokumentiert. @mistralai/mistralai ist außerdem unter MAL-2026-3432 in der OSSF-Datenbank für schädliche Pakete registriert (GHSA-3q49-cfcf-g5fm).
So funktionierte der Angriff: drei miteinander verkettete Schwachstellen
Das Postmortem von TanStack ist detailliert. Es wurden drei Schwachstellen miteinander verkettet; keine davon wäre allein ausreichend gewesen.
Schritt 1: Pwn Request über pull_request_target
Am 10. Mai 2026 erstellte der Angreifer unter dem Konto zblgg (GitHub-ID 127806521) einen Fork von TanStack/router. Er nannte ihn gezielt zblgg/configuration, damit er bei der Suche in Fork-Listen nicht auffiel. Ein schädlicher Commit (65bf499d) wurde unter der erfundenen Identität claude <claude@users.noreply.github.com> verfasst, die die Anthropic-Claude-GitHub-App imitierte. Der Commit erhielt das Präfix [skip ci], um automatisierte CI-Läufe bei Pushes zu unterbinden.
Am 11. Mai um 10:49 Uhr eröffnete der Angreifer PR #7378 gegen TanStack/router#main mit dem Titel „WIP: simplify history build“ und löste eine bekannte Fehlkonfiguration aus: TanStacks Workflow bundle-size.yml verwendete den Trigger pull_request_target, checkte aber den Merge-Ref des Forks aus und führte vom Fork kontrollierten Code aus:
Dieses „Pwn Request“-Muster wurde erstmals im Mai 2024 vom Sicherheitsforscher Adnan Khan dokumentiert und bei Angular, MDN und hyperledger/besu demonstriert. Der Trigger pull_request_target läuft im Sicherheitskontext des Basis-Repos. Dadurch konnte der Code des Forks auf den Cache-Bereich und das GITHUB_TOKEN des Basis-Repos zugreifen.
Schritt 2: Cache-Poisoning in GitHub Actions
Die schädliche Datei vite_setup.mjs aus dem Fork exfiltrierte nicht sofort Daten. Stattdessen vergiftete sie den pnpm-Paketspeicher unter genau dem Cache-Schlüssel, nach dem release.yml später suchen würde:
Dieser Schlüssel wurde anhand der öffentlichen Datei pnpm-lock.yaml mit derselben Formel hashFiles('**/pnpm-lock.yaml') vorab berechnet, die auch der Workflow verwendet. Der vergiftete Cache-Eintrag mit einer Größe von 1,1 GB wurde um 11:29 Uhr gespeichert und blieb fast acht Stunden unentdeckt – bis ein legitimer Push auf den Branch main um 19:15 Uhr release.yml auslöste.
Der Autor von bundle-size.yml hatte versucht, die Vertrauensbereiche zu trennen: Der Benchmark-Job wurde separat gehalten und mit einem Hinweis auf nicht vertrauenswürdige Berechtigungen versehen. Dabei übersah er jedoch ein wichtiges Verhalten von GitHub Actions: Beim Speichern nach dem Job verwendet actions/cache@v5 ein internes Runner-Token und nicht das Workflow-GITHUB_TOKEN. Deshalb verhindert permissions: contents: read keine Schreibzugriffe auf den Cache. Außerdem wird der Cache-Bereich zwischen pull_request_target-Läufen und Pushes auf den Basis-Branch geteilt, wodurch ein Zeitfenster für grenzüberschreitendes Cache-Poisoning entsteht.
Schritt 3: OIDC-Token aus dem Arbeitsspeicher des Runners auslesen
release.yml verfügt über die Berechtigung id-token: write, die für die OIDC-Bindung als vertrauenswürdiger Publisher von npm erforderlich ist. Als während der Build-Phase vom Angreifer kontrollierte Binärdateien aus dem vergifteten pnpm-Speicher ausgeführt wurden, nutzten sie eine Technik, die bei der Kompromittierung von tj-actions/changed-files im März 2025 dokumentiert wurde. Im TanStack-Postmortem heißt es, der Angreifer habe „dieselbe Technik zum Auslesen des Arbeitsspeichers (und ein identisches Python-Skript mit Quellenangabe im Kommentar)“ aus diesem Vorfall verwendet:
Den Prozess
Runner.Workerüber/proc/*/cmdlinefinden/proc/<pid>/mapsund/proc/<pid>/memauslesen, um den Adressraum des Workers auszulesenDas OIDC-Token extrahieren, das der Runner bei gesetztem
id-token: writeverzögert im Arbeitsspeicher erzeugtDirekt authentifiziert als legitimer TanStack-Release-Workflow einen POST an
registry.npmjs.orgsenden
Der vorgesehene Workflow-Schritt Publish Packages wurde nie erreicht, die Tests schlugen fehl und der Schritt wurde übersprungen. Trotzdem wurden Pakete mit einem gültigen OIDC-Token und gültiger SLSA-Provenienz schädlich veröffentlicht, weil der Angreifer das Token vor Abschluss des Workflows ausgelesen hatte.
Es gab zwei Release-Läufe. Beide endeten mit status: failure. npm erhielt 84 gültige, signierte und mit Provenienzattestierungen versehene Paketveröffentlichungen: Lauf 25613093674 und 25691781302.
Im Payload: router_init.js
Die 2,3 MB große Datei router_init.js wurde unbemerkt im Stammverzeichnis jedes kompromittierten Tarballs abgelegt. Sie war nicht im Feld files des Pakets deklariert, was beweist, dass der Tarball außerhalb des normalen Build-Prozesses manipuliert wurde. Außerdem wurde jedem Paket ein Eintrag in optionalDependencies hinzugefügt:
Der Commit-Hash verweist auf einen verwaisten Commit im Fork des Angreifers, den GitHub aufgrund des gemeinsamen Speichers für Commit-Objekte in Fork-Netzwerken über die legitime URL von TanStack/router anzeigt. Die URL wirkt offiziell, der Commit ist es nicht. Löst npm die Abhängigkeit auf, lädt es einen prepare-Lifecycle-Hook herunter und führt ihn aus:
Das && exit 1 ist beabsichtigt: Die optionale Abhängigkeit „schlägt“ ordnungsgemäß fehl und hinterlässt kaum Spuren in den Installationsprotokollen, während der Payload bereits im Hintergrund ausgeführt wird.
Ein wichtiger Hinweis zur Abwehr: Bun führt als Paketmanager standardmäßig keine Lifecycle-Skripte aus. Entwicklerinnen und Entwickler, die die betroffenen Pakete direkt mit Bun installieren, hätten diesen konkreten Payload-Auslieferungsvektor daher nicht ausgelöst. Auf Rechnern, auf denen Bun bereits installiert ist, wird außerdem durch die Prüfung hasCommand("bun") ein vorzeitiger Abbruch im Payload ausgelöst. Beides macht Bun nicht zu einer vollständigen Schutzmaßnahme: Die Datei router_init.js befindet sich weiterhin im Tarball. Es verringert jedoch die Angriffsfläche während der Installation.
Drei Verschleierungsebenen
router_init.js verwendet ein dreischichtiges Schutzschema, das in der vollständigen Entschlüsselung von Upwind Security dokumentiert ist. Dabei erzeugte webcrack 2.16.0 aus dem 11,7 MB großen verschleierten Blob 221.771 Zeilen lesbares JavaScript:
Ebene 1: Das klassische Muster des JavaScript-Obfuscators: Auf einen selbstaufrufenden Bootstrap zur Rotation eines String-Arrays folgt eine Dispatcher-Funktion (_0x253b), die 2.864-mal in einer einzigen Quellcodezeile aufgerufen wird. Alle Zeichenfolgenliterale werden durch Array-Zugriffe ersetzt.
Ebene 2: Eine Substitutionschiffre nach Fisher-Yates, die jedes Byte einzeln verarbeitet. Der Schlüssel wird mit PBKDF2-SHA256 abgeleitet, unter Verwendung des hartcodierten Hauptschlüssels 0c0e873033875f1bc471eda37e3b9d0f9b89bd41a4bbb4f86746caa2186c40aa und des Salts svksjrhjkcejg bei 200.000 Durchläufen – absichtlich langsam, um automatisierte Analysen zu erschweren. Diese Ebene entschlüsselt 396 eindeutige Zeichenfolgenkonstanten, darunter C2-Domains, Pfade zu Zugangsdaten und den internen Namen der Kampagne: EveryBoiWeBuildIsAWormyBoi.
Ebene 3: Elf AES-256-GCM-verschlüsselte, gzip-komprimierte Payloads, zu deren Entschlüsselung die Bun-Laufzeit (Bun.gunzipSync) erforderlich ist. Die durch die Entschlüsselung wiederhergestellte Verschlüsselungsfunktion:
Derselbe ctf-scramble-v2-Fisher-Yates-PRNG (mit 0x3039 / 12345 als Seed) findet sich wortgetreu in den Bitwarden-CLI-, SAP- und TanStack-Wellen wieder — Unit 42 identifizierte dies als Hinweis auf eine gemeinsame Urheberschaft, der alle drei Angriffe derselben Codebasis zuordnet.
Als Daemon ausführen
Bevor die Payload irgendetwas Sichtbares unternimmt, prüft sie process.env.__DAEMONIZED. Ist die Variable nicht gesetzt, startet sie einen vollständig abgekoppelten Child-Prozess, unterdrückt sämtliche Standard-Ein- und -Ausgaben und ruft unref() auf, damit Node.js nicht auf den Child-Prozess wartet. Der Parent-Prozess wird sauber beendet; der Child-Prozess läuft unbemerkt und ist von der Terminalsitzung entkoppelt, in der npm install ausgeführt wurde.
Abschöpfen von Zugangsdaten
Die Payload durchsucht systematisch alle wichtigen Zugangsdatenebenen in cloud-nativen CI-Umgebungen. Beachten Sie: Der Scraper für den Runner-Arbeitsspeicher überspringt absichtlich Tokens mit dem expliziten Namen github_token — vermutlich, um zu verhindern, dass GitHubs eigene Geheimniserkennung die exfiltrierten Daten entdeckt.
GitHub Actions:
Direkte Zugriffe:
GITHUB_REPOSITORY,GITHUB_SERVER_URL,ACTIONS_ID_TOKEN_REQUEST_TOKEN,ACTIONS_ID_TOKEN_REQUEST_URLGitHub-REST-API:
GET /repos/<repo>/actions/secrets?per_page=100(das API-Maximum)
AWS:
Umgebungsvariablen:
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION,AWS_ROLE_ARN,AWS_WEB_IDENTITY_TOKEN_FILEIMDSv2 (korrekt implementiert — funktioniert auch mit gehärteten Instanzen, auf denen IMDSv1 deaktiviert ist)
ECS-Task-Metadaten-Endpunkt (
169.254.170.2)Auflistung von Secrets Manager und SSM Parameter Store über mehrere Regionen hinweg
HashiCorp Vault:
VAULT_TOKEN,VAULT_ADDR,VAULT_AUTH_TOKENDirekte API-Aufrufe an
vault.svc.cluster.local:8200(den internen Vault-Endpunkt von Kubernetes)
Kubernetes:
Service-Account-Tokens unter
/var/run/secrets/kubernetes.io/serviceaccount/In Kombination mit dem Vault-Endpunkt: K8s-Token stehlen → bei Vault authentifizieren → alle Vault-Secrets abrufen
Workstation-Ziele:
~/.npmrc,~/.git-credentials, private SSH-Schlüssel unter~/.ssh/GCP-Metadaten, Zugangsdaten-Dateien von Cloud-Anbietern an über 100 Pfaden unter Linux und macOS
~/.claude/projects/*.jsonl— Claude-Code-Sitzungsverlaufsdateien mit Code, Befehlen und potenziell Zugangsdaten aus früheren Claude-Code-Sitzungen
Bei der Entschleierung wiederhergestellte Token-RegEx-Muster:
Exfiltration und Dead Drops
Gestohlene Daten werden verschlüsselt über das dezentrale P2P-Messenger-Netzwerk Session/Oxen versendet (filev2.getsession[.]org, seed{1,2,3}.getsession.org). Es gibt keinen vom Angreifer kontrollierten C2-Server; der Datenverkehr wird über die onion-basierten Service-Nodes von Session geleitet und ist von verschlüsselter Messenger-App-Telemetrie nicht zu unterscheiden. Eine Blockierung auf IP-Ebene ist wirkungslos; die DNS-Blockierung von *.getsession.org ist die praktikable Perimeter-Kontrolle.
Ein weiterer Exfiltrationsweg führt über GitHubs eigene GraphQL-API mittels Dead-Drop-Commits: erstellt unter claude@users.noreply.github.com (unter falscher Identität der Anthropic-Claude-GitHub-App), mit der Nachricht chore: update dependencies und Dependabot-ähnlichen Branch-Namen aus Frank Herberts Dune-Universum, dependabout/…/setup-formatter (Hinweis: „dependabout“, nicht „dependabot“). GitHubs GraphQL-Endpunkt ist in praktisch jeder CI-Netzwerk-Egress-Richtlinie freigegeben, sodass dieser Kanal Perimeter-Kontrollen vollständig umgeht.
Die Payload fügt außerdem .github/workflows/codeql_analysis.yml in jedes zugängliche Repository ein und exfiltriert bei jedem Push toJSON(secrets) — so werden sämtliche GitHub-Actions-Secrets aus dem Kontext der betroffenen Organisationen abgeschöpft.
Ein Mechanismus zur Wiederherstellung im Notfall durchsucht GitHub nach Commits mit der magischen Zeichenfolge OhNoWhatsGoingOnWithGitHub, um Tokens wiederherzustellen, die zuvor von anderen Opfern exfiltriert wurden.
Selbstverbreitung
Nach dem Exfiltrieren der Zugangsdaten fragt der Wurm Folgendes ab:
Anschließend veröffentlicht er jedes Paket unter der gestohlenen OIDC-Identität erneut – mit derselben router_init.js-Injektion und demselben optionalDependencies-Eintrag. Wie in Snyks Security Database dokumentiert, weitete sich die Verbreitung über die ursprünglichen 84 @tanstack/*-Versionen hinaus auf mehr als 200 Pakete aus. Dadurch verbreitete sich der Wurm auf Mistral AI, UiPath und Dutzende weitere Folgeopfer.
Entscheidend ist, dass der Wurm mit generateKeyPairSync und sign Sigstore-kompatible in-toto-Provenance-Attestierungen für jedes erneut veröffentlichte Paket fälscht. Damit enthalten auch die Pakete der Folgeopfer scheinbar gültige SLSA-Provenance. Das Versagen der SLSA-Attestierung betrifft also auch vom Wurm verbreitete Pakete und nicht nur die ursprüngliche TanStack-Veröffentlichung.
Persistenz: Deinstallieren reicht nicht
Der Wurm legt Kopien von sich selbst in Entwickler-Tool-Verzeichnissen ab, um npm uninstall und Neustarts zu überstehen:
Claude-Code-Hooks (.claude/):
Die hooks-Konfiguration von Claude Code kann als Reaktion auf Tool-Ereignisse wie Dateiänderungen und Bash-Ausführungen Shell-Befehle starten. Indem sich der Wurm in .claude/settings.json einträgt, wird er jedes Mal erneut ausgeführt, wenn eine Entwicklerin oder ein Entwickler Claude Code im betroffenen Projektverzeichnis verwendet.
VS Code (.vscode/):
Die automatische Ausführung von Workspace-Tasks in VS Code bietet einen unabhängigen Ausführungsweg. Zusammen sorgen diese beiden Mechanismen dafür, dass eine Person, die npm install mit einer betroffenen Version ausgeführt hat, ihre Umgebung jedes Mal erneut kompromittieren kann, wenn sie den Editor öffnet.

Nx-NPM-Malware erklärt: Hijacking von KI-Agenten — Wie Supply-Chain-Malware VS-Code-Tasks und Hooks von KI-Coding-Agenten als Persistenzmechanismen missbraucht, mit einer Analyse der Nx-NPM-Wurm-Kampagne, die identische Techniken einsetzte.
Systemweiter Totmannschalter:
Dieser Dienst fragt alle 60 Sekunden mit dem gestohlenen GitHub-Token api.github.com/user ab. Wird das Token widerrufen (HTTP-Antwort 40x), führt der Dienst rm -rf ~/ aus und löscht damit das Home-Verzeichnis der betroffenen Person.
Die Reihenfolge der Gegenmaßnahmen ist wichtig: Deaktivieren Sie den Überwachungsdienst, bevor Sie Zugangsdaten widerrufen. Wenn Sie zuerst widerrufen, kann dadurch das Löschen des Home-Verzeichnisses ausgelöst werden. Darauf wies unabhängig der Forscher carlini in einem Kommentar zu GitHub-Issue #4425225340 hin; die HN-Community machte den Befund innerhalb weniger Stunden nach dem Angriff bekannt.
Das SLSA-Provenance-Problem
Dieser Angriff ist der erste dokumentierte Fall eines NPM-Wurms, der gültig attestierte SLSA-Build-Level-3-Provenance für bösartige Pakete erzeugt. Die Sigstore-Attestierungen für die kompromittierten Versionen von @tanstack/* sind legitim: Sie bestätigen korrekt, dass die Pakete von release.yml ausgeführt auf refs/heads/main im Repository TanStack/router gebaut und veröffentlicht wurden. Das stimmt alles.
SLSA-Provenance bestätigt, dass ein Paket durch einen GitHub-Actions-Lauf eines bestimmten Repositorys erstellt wurde. Sie bestätigt nicht, dass der Workflow ausgeführt werden durfte, dass er von einem geschützten Branch gestartet wurde oder dass der auslösende Commit legitim war.
Die ausnutzbare OIDC-Konfiguration:
Die sichere Konfiguration:
Jedes NPM-Paket, das OIDC Trusted Publishing ohne Festlegung von Branch und Workflow-Datei verwendet, ist für diese Art von Angriff anfällig. Provenance-Attestierungen sind ein notwendiger Bestandteil der Supply-Chain-Sicherheit, aber kein ausreichender. Die Verhaltensanalyse bei der Installation ist eine ergänzende Schutzmaßnahme. Automatisierte Verhaltensanalyse erkannte alle 84 betroffenen Artefakte innerhalb von sechs Minuten nach ihrer Veröffentlichung, indem sie Anomalien in router_init.js feststellte – noch bevor menschliche Analystinnen oder Analysten die Pakete geprüft hatten.
Was Sie jetzt tun sollten
Schritt 0: Prüfen, ob Sie betroffen sind
Prüfen Sie, ob eine betroffene Version in Ihre Umgebungen gelangt ist, ohne Skripte auszuführen:
Schritt 1: Persistenz beseitigen, BEVOR Sie Zugangsdaten rotieren
Wenn Sie Hinweise auf eine Kompromittierung finden, deaktivieren Sie zuerst den Totmannschalter:
Entfernen Sie anschließend die Persistenz-Hooks im Editor:
Schritt 2: Alle Secrets rotieren
Nachdem die Persistenz beseitigt wurde, rotieren Sie die Zugangsdaten in dieser Reihenfolge:
NPM-Veröffentlichungstokens und OIDC-Federation-Grants für alle NPM-Pakete, die aus betroffenen Repositorys veröffentlicht wurden
GitHub-PATs und personalisierte Zugriffstokens mit eingeschränkten Berechtigungen
AWS-Zugangsdaten (sowohl statische Schlüssel als auch Vertrauensstellungen für Instanzrollen über IMDSv2)
HashiCorp-Vault-Tokens
Kubernetes-Service-Account-Tokens
Private SSH-Schlüssel
GCP-Service-Account-Zugangsdaten
Alle Secrets, die in
~/.claude/projects/*.jsonlsichtbar sind — Claude-Code-Sitzungsprotokolle werden gezielt abgeschöpft
Richten Sie OIDC-Federation-Grants erst dann wieder ein, wenn Sie bestätigt haben, dass der Veröffentlichungs-Workflow sauber ist.
Schritt 3: Maßnahmen auf Netzwerkebene
Sperren Sie *.getsession.org auf DNS-Ebene. Eine Sperrung auf IP-Basis reicht nicht aus — das Session-Netzwerk nutzt verteilte Service-Nodes. Die DNS-Blockierung ist die praktikable Perimeter-Kontrolle.
Sperren Sie außerdem: api.masscan.cloud und git-tanstack.com (weitere C2-Domains aus der Kampagneninfrastruktur). Sperren Sie ausgehende Verbindungen zu den URLs der Second-Stage-Payloads: litter.catbox.moe/h8nc9u.js und litter.catbox.moe/7rrc6l.mjs.
Schritt 4: OIDC-Konfiguration von GitHub Actions prüfen
Legen Sie für jedes NPM-Paket mit Trusted Publishing in der OIDC-Konfiguration einen bestimmten Branch und eine bestimmte Workflow-Datei fest:
Setzen Sie auf Workflow-Ebene permissions: id-token: none und gewähren Sie id-token: write nur für den Job, der das Paket veröffentlicht:
Schritt 5: pull_request_target-Workflows prüfen
Jeder Workflow mit pull_request_target, der zugleich Code aus Forks auscheckt und in den Cache schreibt, ist für den Cache-Poisoning-Angriff anfällig. Verwenden Sie entweder pull_request (Fork-Kontext, schreibgeschützt) oder trennen Sie die Ausführung von Fork-Code vollständig von Schreibvorgängen im Cache des Basis-Repositorys.
Löschen Sie vorhandene GitHub-Actions-Caches für alle Repositorys, in denen pull_request_target zusammen mit Cache-Schreibvorgängen verwendet wird:
Fixieren Sie alle Referenzen auf Drittanbieter-Actions auf Commit-SHAs statt auf Tags:
Schritt 6: Wartezeiten für neue Releases einführen
Die bösartigen Versionen waren etwa drei Stunden lang verfügbar. Eine siebentägige Wartezeit hätte vor diesem konkreten Angriff vollständig geschützt (siehe auch: Einstellungen zur Härtung der pnpm-Supply-Chain):
Erwägen Sie außerdem allow-git=none für npm v11+, um die Installation von Abhängigkeiten über Git-URLs zu verhindern (Angriffsvektor für die optionale Abhängigkeit @tanstack/setup).
Schritt 7: Vertrauen Sie nicht allein auf SLSA-Provenance
Dieser Angriff erzeugt gültige SLSA-Build-Level-3-Attestierungen für bösartige Pakete. Die Überprüfung der Provenance ist notwendig, aber nicht ausreichend. Kombinieren Sie sie mit einer Verhaltensanalyse zum Installationszeitpunkt und einem Tool, das Pakete auf bekannte bösartige Signaturen prüft.
Snyks Abdeckung
Snyks Security Database deckt den damit verbundenen Supply-Chain-Angriff auf LiteLLM über PyPI ab (SNYK-PYTHON-LITELLM-15762713). Dabei wurden manipulierte Versionen von litellm direkt auf PyPI hochgeladen, die mithilfe derselben .pth-Dateitechnik einen mehrstufigen Zugangsdaten-Dieb und eine persistente Hintertür installierten.
Snyks ausführliche Analyse des LiteLLM-Angriffs finden Sie unter snyk.io/articles/poisoned-security-scanner-backdooring-litellm.
Snyk Open Source scannt Ihren Abhängigkeitsbaum anhand der Snyk Security Database und kennzeichnet bekannte kompromittierte Paketversionen. Wenn Sie Ihre Projekte noch nicht scannen, testen Sie Snyk kostenlos, um Ihre aktuelle Gefährdung zu prüfen.

Shai-Hulud-NPM-Angriff: Mit Snyk Gegenmaßnahmen ergreifen — Eine Anleitung dazu, wie Sie mit Snyk kompromittierte Pakete in Ihrem Abhängigkeitsbaum identifizieren und die Gefährdung beseitigen.
Zusammenfassung: Kompromittierungsindikatoren
Indikator | Wert |
|---|---|
CVE | CVE-2026-45321 |
GHSA | GHSA-g7cv-rxg3-hmpx |
Bösartige Datei |
|
SHA-256 ( |
|
SHA-256 ( |
|
Bösartige |
|
Angreifer-Fork | |
Bösartiger verwaister Commit |
|
Primäre Exfiltrations-Domain |
|
Zusätzliche C2-Domains |
|
Second-Stage-Payloads |
|
Autor des Dead-Drop-Commits |
|
Dead-Drop-Branch-Muster |
|
Persistenzdateien |
|
Totmannschalter (Linux) |
|
Totmannschalter (macOS) |
|
PBKDF2-Salt der Kampagne |
|
Kampagnenzeichenfolge |
|
Von der Community gepflegte Erkennungsskripte: GLPMC/Tanstack-Worm-Detector und omarpr/mini-shai-hulud-ioc-scanner (bitte überprüfen Sie diese jedoch vor der Verwendung).
Sichern Sie Ihre Python-Apps ab
Finden und beheben Sie Python-Schwachstellen – kostenlos mit Snyk.
Keine Kreditkarte erforderlich.
Oder registrieren Sie sich mit Azure AD Docker ID Bitbucket
Mit der Nutzung von Snyk erklären Sie sich mit unseren Richtlinien einverstanden, einschließlich unserer Nutzungsbedingungen und Datenschutzerklärung.
