Postmortem: TanStack npm-Lieferkettenkompromittierung
(tanstack.com)- Am 2026-05-11 zwischen 19:20 und 19:26 UTC veröffentlichte ein Angreifer 84 bösartige Versionen in 42 @tanstack/-npm-Paketen
- Die Angriffskette kombinierte einen pull_request_target-„Pwn Request“, GitHub-Actions-Cache-Vergiftung und das Extrahieren von OIDC-Tokens aus dem Runner-Speicher
- npm-Token und der Publish-Workflow wurden weder gestohlen noch kompromittiert; die Schadsoftware führte stattdessen direkte POSTs an die Registry mit OIDC trusted publisher-Rechten aus
- Bei der Installation betroffener Versionen könnten AWS-, GCP-, Kubernetes-, Vault-, GitHub-, npm- und SSH-Zugangsdaten offengelegt worden sein und sollten ersetzt werden
- Alle betroffenen Versionen wurden als deprecated markiert, mit npm security wurde die Entfernung der Tarballs eingeleitet, und ein Tracking-Issue sowie ein GitHub Security Advisory wurden veröffentlicht
Überblick über den Vorfall
- Zwischen 19:20 und 19:26 UTC am 2026-05-11 veröffentlichte ein Angreifer 84 bösartige Versionen in 42
@tanstack/*-npm-Paketen - Die Angriffskette kombinierte das
pull_request_target-„Pwn Request“-Muster, eine GitHub-Actions-Cache-Vergiftung über die Vertrauensgrenze zwischen Fork und Base hinweg sowie das Extrahieren von OIDC-Tokens aus dem Prozessspeicher von GitHub-Actions-Runnern - Es wurde bestätigt, dass keine npm-Token gestohlen wurden und auch der npm-Publish-Workflow selbst nicht kompromittiert war
- Die bösartigen Versionen wurden vom externen Forscher
ashishkurmibeistepsecurityöffentlich innerhalb von 20 Minuten entdeckt - Alle betroffenen Versionen wurden als deprecated markiert, und zusammen mit npm security wurde die Entfernung der Tarballs aus der Registry eingeleitet
- Nutzer, die am 2026-05-11 betroffene Versionen installiert haben, müssen AWS-, GCP-, Kubernetes-, Vault-, GitHub-, npm- und SSH-Zugangsdaten, auf die vom Installations-Host aus zugegriffen werden konnte, ersetzen
- Das Tracking-Issue ist TanStack/router#7383, das GitHub Security Advisory ist GHSA-g7cv-rxg3-hmpx
Betroffene Reichweite
-
Betroffene Pakete
- Der Umfang umfasst 42 Pakete und 84 Versionen; pro Paket wurden zwei Versionen im Abstand von etwa 6 Minuten veröffentlicht
- Die vollständige Liste ist im Tracking-Issue enthalten
- Als sicher nicht betroffene Produktfamilien bestätigt sind
@tanstack/query*,@tanstack/table*,@tanstack/form*,@tanstack/virtual*,@tanstack/storeund das Meta-Paket@tanstack/start @tanstack/start-*ist nicht in der bestätigten Liste nicht betroffener Pakete enthalten
-
Verhalten der Schadsoftware
- Wenn eine Entwickler- oder CI-Umgebung für betroffene Versionen
npm install,pnpm installoderyarn installausführt, wertet npm den bösartigenoptionalDependencies-Eintrag aus und holt einen verwaisten Payload-Commit aus dem Fork-Netzwerk - Anschließend wird das Lifecycle-Skript
prepareausgeführt, wobei die im betroffenen Tarball versteckte, etwa 2,3 MB große obfuskierte Dateirouter_init.jsaktiv wird - Das bösartige Skript sammelt Zugangsdaten aus gängigen Speicherorten, darunter AWS IMDS/Secrets Manager, GCP-Metadaten, Kubernetes-Service-Account-Token, Vault-Token,
~/.npmrc, GitHub-Token, diegh-CLI,.git-credentials, SSH-Private-Key und weitere - Die exfiltrierten Daten werden über das Session/Oxen-Messenger-File-Upload-Netzwerk übertragen; Zielsysteme sind
filev2.getsession.orgundseed{1,2,3}.getsession.org - Da dieses Netzwerk Ende-zu-Ende-verschlüsselt ist und kein vom Angreifer kontrolliertes C2 besitzt, bleiben als Netzwerkminderung nur IP-/Domain-Sperren
- Die Logik zur Selbstverbreitung zählt mit
registry.npmjs.org/-/v1/search?text=maintainer:<user>weitere vom Opfer gepflegte Pakete auf und veröffentlicht sie anschließend mit derselben Injektionsmethode erneut - Da die Payload als Teil des npm-install-Lifecycles ausgeführt wird, sollten Hosts, die am 2026-05-11 betroffene Versionen installiert haben, als potenziell kompromittiert behandelt werden
- Wenn eine Entwickler- oder CI-Umgebung für betroffene Versionen
Zeitleiste
-
Vor dem Angriff: Phase der Cache-Vergiftung
- Am 2026-05-10 um 17:16 UTC erstellte der Angreifer github.com/zblgg/configuration, einen Fork von TanStack/router, und änderte den Namen, um die Suche in der Fork-Liste zu umgehen.
- Am 2026-05-10 um 23:29 UTC wurde mit der manipulierten Identität
claude <claude@users.noreply.github.com>der schädliche Commit65bf499d16a5e8d25ba95d69ec9790a6dd4a1f14in den Fork geschrieben. - Dieser Commit fügte
packages/history/vite_setup.mjshinzu, einen gebündelten JS-Payload mit rund 30.000 Zeilen, und versah die Commit-Message mit[skip ci], um die CI bei Push-Events zu unterdrücken. - Am 2026-05-11 gegen 10:49 UTC eröffnete
zblggden PR #7378 gegen TanStack/routermainmit dem Titel „WIP: simplify history build“. bundle-size.ymlundlabeler.ymlwurden beide für den PR automatisch überpull_request_targetausgeführt; dapull_request_targetdas Freigabe-Gate für Erstbeitragende umgeht, war keine separate Freigabe erforderlich.pr.yml, daspull_requestverwendet, blieb wegen ausstehender Freigabe blockiert und wurde nicht ausgeführt.- Zwischen 11:01 und 11:11 UTC am 2026-05-11 führte
zblggmehrfach Force-Pushes auf den PR-Head aus und löste dadurch zusätzlichepull_request_target-Ausführungen aus. - Am 2026-05-11 um 11:11 UTC landete der schädliche Commit
65bf499dauf dem PR-Head, und der Jobbenchmark-prausbundle-size.ymlcheckte anschließendrefs/pull/7378/mergeaus und führtepnpm installsowiepnpm nx run @benchmarks/bundle-size:buildaus, wodurchvite_setup.mjsausgeführt wurde. - Am 2026-05-11 um 11:29 UTC wurde in TanStack/router ein 1,1-GB-GitHub-Actions-Cache mit dem Namen
Linux-pnpm-store-6f9233a50def742c09fde54f56553d6b449a535adf87d4083690539f49ae4da11gespeichert. - Dieser Cache wurde im Scope
refs/heads/maingespeichert und so aufgebaut, dass er zu dem Schlüssel passte, denrelease.ymlbeim nächsten Push aufmainabrufen würde. - Am 2026-05-11 um 11:31 UTC setzte der Angreifer den PR auf den damaligen
main-HEADb1c061afzurück, sodass der sichtbare PR wie ein 0-Dateien-No-op aussah, und schloss im selben Moment den PR und löschte den Branch, aber der vergiftete Cache blieb bestehen.
-
Auslösung: Veröffentlichungsphase
- Am 2026-05-11 um 19:15 UTC löste Manuel durch das Mergen von PR #7369 einen Push auf
mainaus; daraufhin startete der Workflow-Run25613093674vonrelease.ymlum 19:15:44 und schlug anschließend fehl. - Am 2026-05-11 um 19:20:39 UTC empfing die npm-Registry die Veröffentlichungen von
@tanstack/history@1.161.9und 41 zugehörigen Paketen. - Insgesamt wurden über 42 Pakete hinweg etwa 84 Versionen veröffentlicht, aber zu genau diesem Zeitpunkt war nur ungefähr die Hälfte sichtbar; der Rest wurde im zweiten Run veröffentlicht.
- Die Publish-Authentifizierung erfolgte über ein OIDC trusted-publisher binding für TanStack/router
release.yml@refs/heads/main, sie stammte jedoch nicht aus dem StepPublish Packagesdes wegen fehlgeschlagener Tests übersprungenen Workflows. - Der tatsächliche Publisher war die Malware, die während der Test-/Bereinigungsschritte ausgeführt wurde; sie mintete mit der Berechtigung
id-token: writeein OIDC-Token und sendete dann direkt einen POST anregistry.npmjs.org. - Am 2026-05-11 um 19:20:47 UTC wurde Run
25613093674mit dem Status failure abgeschlossen. - Am 2026-05-11 um 19:16 UTC löste Manuel durch das Mergen von PR #7382 einen zweiten Push auf
mainaus, und um 19:16:22 begann Workflow-Run25691781302. - Auch der zweite Run stellte denselben vergifteten Cache wieder her, und am 2026-05-11 um 19:26:14 UTC wurde mit demselben OIDC-Mechanismus ein zweiter Versionssatz pro Paket veröffentlicht, darunter
@tanstack/history@1.161.12. - Am 2026-05-11 um 19:26:20 UTC wurde auch Run
25691781302mit dem Status failure abgeschlossen.
- Am 2026-05-11 um 19:15 UTC löste Manuel durch das Mergen von PR #7369 einen Push auf
-
Erkennung und Reaktion
- Am 2026-05-11 gegen 19:50 UTC eröffnete der externe Forscher
carlinidas Issue #7383 mit einem schädlichenoptionalDependencies-Fingerprint und einer Paketliste. - Die erste Liste umfasste 14 von 42 Paketen, und der Forscher informierte auch direkt npm security.
- Am 2026-05-11 gegen 20:00 UTC bestätigte Manuel in #7383 den Vorfall und begann mit der Reaktion.
- Am 2026-05-11 gegen 20:10 UTC entfernte Manuel die GitHub-Push-Berechtigungen anderer Teammitglieder, um auf eine mögliche Kompromittierung von Benutzerrechnern vorbereitet zu sein.
- Am 2026-05-11 gegen 20:30 UTC schickte Tanner die vollständige IOC-Liste und die Anfrage zur Entfernung der Tarballs auf Registry-Seite an security@npmjs.com und reichte über npm einen formalen Malware-Report ein.
- Am 2026-05-11 gegen 21:00 UTC bestätigte ein vollständiger Scan aller 295
@tanstack/*-Pakete den Umfang mit 42 Paketen und 84 Versionen. - Tanner begann mit der npm-Deprecation aller 84 betroffenen Pakete, und
@tan_stacksowie die Maintainer veröffentlichten öffentliche Warnungen auf Twitter/X, LinkedIn und Bluesky. - Am 2026-05-11 um 21:30 UTC wurden der Cache-Vergiftungsvektor über
pull_request_targetinbundle-size.ymlund der Forkzblgg/configurationidentifiziert. - Cache-Einträge aller TanStack/*-GitHub-Repositories wurden per API entfernt.
- Ein Hardening-PR wurde gemergt,
bundle-size.ymlwurde neu konfiguriert, einrepository_owner-Guard wurde hinzugefügt und die Refs von Third-Party-Actions wurden auf SHA festgeschrieben. - Ein offizielles GitHub Security Advisory wurde veröffentlicht und eine CVE beantragt.
- Am 2026-05-11 gegen 19:50 UTC eröffnete der externe Forscher
Grundursache
-
Kombination aus drei Schwachstellen
- Für den Angriff waren alle drei Schwachstellen erforderlich; keine einzelne war für sich allein ausreichend.
- Der Fork-PR-Code gelangte in den Cache des Basis-Repositorys, der Cache des Basis-Repositorys in die Runtime des Release-Workflows, und die Runtime des Release-Workflows führte schließlich zu Schreibrechten auf die npm-Registry – so verband jede Schwachstelle die Vertrauensgrenzen der jeweils anderen.
-
pull_request_target-„Pwn Request“-Musterbundle-size.ymlwurde für Fork-PRs mitpull_request_targetausgeführt, checkte in diesem Trigger-Kontext den PR-Merge-Ref des Forks aus und führte dann den Build aus.- Die Kernstruktur sah wie folgt aus.
on: pull_request_target: paths: ['packages/**', 'benchmarks/**'] jobs: benchmark-pr: steps: - uses: actions/checkout@v6.0.2 with: ref: refs/pull/${{ github.event.pull_request.number }}/merge # fork's merged code - uses: TanStack/config/.github/setup@main # transitively calls actions/cache@v5 - run: pnpm nx run @benchmarks/bundle-size:build # executes fork-controlled code- Die Verfasser des Workflows versuchten, die Vertrauensgrenzen zu trennen, indem sie den
comment-pr-Job und denbenchmark-pr-Job separierten; in einem YAML-Kommentar stand, dassbenchmark-prals „untrusted with read-only permissions“ beibehalten werden sollte. - Das Post-Job-Speichern von
actions/cache@v5wird jedoch nicht durchpermissions:blockiert, und Cache-Schreibzugriffe verwenden nicht dasGITHUB_TOKENdes Workflows, sondern ein internes Token des Runners. - Daher konnte die Einstellung
permissions: contents: readdie Mutation des Caches nicht verhindern. - Der Cache-Scope ist auf Repository-Ebene, und ein
pull_request_target-Run mit dem Cache-Scope des Basis-Repositorys wird zusammen mit einemmain-Push geteilt. - Ein PR, der im Cache-Scope des Basis-Repositorys läuft, kann daher einen Cache-Eintrag vergiften, den später der Production-Workflow von
mainwiederherstellt.
-
Vergiftung des GitHub-Actions-Caches
- Die bösartige
vite_setup.mjswar so entworfen, dass sie Daten passend zu dem pnpm-store-Schlüssel schreibt, den der legitime Workflowrelease.ymlberechnet und abfragt. - Der Zielschlüssel hatte das Format
Linux-pnpm-store-${hashFiles('**/pnpm-lock.yaml')}. - Beim Ende des
benchmark-pr-Jobs speicherte der Post-Step vonactions/cache@v5den vergifteten pnpm-Store unter genau diesem Schlüssel. - Als später bei einem
main-Pushrelease.ymlausgeführt wurde, stellte der StepSetup Toolsden vergifteten Eintrag wie vorgesehen wieder her. - Dieser Angriffstyp gehört zur Klasse der GitHub-Actions-Cache-Poisoning-Angriffe, die 2024 von Adnan Khan dokumentiert wurden; es handelt sich nicht um einen auf TanStack beschränkten Bug, sondern um ein Designproblem von GitHub Actions, das bewusste Gegenmaßnahmen erfordert.
- Die bösartige
-
Extraktion des OIDC-Tokens aus dem Runner-Speicher
release.ymldeklariert berechtigterweiseid-token: write, da dies für npm OIDC trusted publishing benötigt wird.- Wenn der vergiftete pnpm-Store auf dem Runner wiederhergestellt wird, befindet sich eine vom Angreifer kontrollierte Binärdatei auf der Platte und wird im Build-Step aufgerufen.
- Diese Binärdatei findet über
/proc/*/cmdlineden GitHub-Actions-ProzessRunner.Workerund liest/proc/<pid>/mapssowie/proc/<pid>/mem, um den Worker-Speicher zu dumpen. - Anschließend extrahiert sie aus dem Speicher das OIDC-Token, das der Runner unter der Einstellung
id-token: writeper Lazy Minting erzeugt hat. - Mit dem extrahierten Token authentifizierte der Angreifer direkte POST-Anfragen an
registry.npmjs.orgund umging damit den StepPublish Packagesdes Workflows vollständig. - Diese Methode der Speicherextraktion entspricht der Methode, die beim Kompromittierungsfall
tj-actions/changed-filesim März 2025 verwendet wurde; dabei kam dasselbe Python-Skript inklusive Attribution-Kommentar zum Einsatz. - Der Angreifer hat also keine neue Technik erfunden, sondern öffentliche Forschung neu kombiniert.
-
Warum die einzelnen Elemente für sich allein nicht ausreichten
pull_request_targetselbst kann für vertrauenswürdige Aufgaben wie Labels oder Kommentare verwendet werden.- Cache Poisoning innerhalb einer bereits kompromittierten Dependency reicht für sich genommen nicht aus, sondern benötigt zusätzlich ein separates Publish-Vehikel.
- OIDC-Token-Extraktion allein setzt bereits vorhandene Code-Ausführung auf dem Runner voraus.
Erkennung und IOC
-
Erkennungspfad
- Die Erkennung erfolgte nicht intern, sondern von außen.
carlinieröffnete etwa 20 Minuten nach der Veröffentlichung Issue #7383 und lieferte darin eine vollständige technische Analyse.- Tanner erhielt kurz nach Beginn des War Room einen Anruf von Socket.dev, der die Lage bestätigte.
-
Fingerprints für Downstream-Maintainer und Security-Tools
- In den Package-Manifests von
@tanstack/*ist der folgende Eintrag unteroptionalDependenciesder zentrale IOC.
"optionalDependencies": { "@tanstack/setup": "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c" }- Der Datei-IOC ist
router_init.jsim Package-Root; die Datei ist etwa 2,3 MB groß und nicht in"files"enthalten. - Der Cache-Schlüssel lautet
Linux-pnpm-store-6f9233a50def742c09fde54f56553d6b449a535adf87d4083690539f49ae4da11. - Die URLs der Payload der zweiten Stufe sind
https://litter.catbox.moe/h8nc9u.jsundhttps://litter.catbox.moe/7rrc6l.mjs. - Das Exfiltrationsnetzwerk ist
filev2.getsession.org,seed{1,2,3}.getsession.org. - Die gefälschte Commit-Identität lautet
claude <claude@users.noreply.github.com>; dabei handelt es sich nicht um das echte Anthropic Claude, sondern um eine manipulierte GitHub-No-Reply-E-Mail. - Die tatsächlichen Angreiferkonten sind
zblggid 127806521undvoicproducoesid 269549300. - Der Fork des Angreifers ist github.com/zblgg/configuration und wurde zur Umgehung der Suche von einem TanStack/router-Fork umbenannt.
- Der Orphan-Payload-Commit im Fork-Netzwerk ist
79ac49eedf774dd4b0cfa308722bc463cfe5885c. - Die Workflow-Runs, die die bösartige Veröffentlichung durchgeführt haben, sind github.com/TanStack/router/actions/runs/25613093674 Versuch 4 und github.com/TanStack/router/actions/runs/25691781302.
- In den Package-Manifests von
Erkenntnisse
-
Was gut lief
- Externe Forschende entdeckten den Vorfall rund 20 Minuten nach dem Ereignis und meldeten ihn mit vollständigen technischen Details.
- Das Maintainer-Team koordinierte sich sofort über mehrere Zeitzonen hinweg.
- Die Detection-Community hatte innerhalb weniger Stunden klare öffentliche IOC-Muster.
-
Was verbessert werden muss
- Es gab kein internes Alerting, und die Kompromittierung wurde zuerst von Dritten bekannt gemacht.
- Eigenes Publish-Monitoring ist nötig; zudem ist geplant, enger mit Unternehmen für Ökosystem-Sicherheitsforschung zusammenzuarbeiten, die solche Probleme schnell erkennen können, und die Feedback-Schleife zu verkürzen.
- Der
pull_request_target-Workflow war schon lange als riskantes Muster bekannt, wurde aber nicht auditiert. - Floating Refs von Third-Party-Actions wie
@v6.0.2und@mainschaffen unabhängig von diesem Vorfall ein dauerhaftes Supply-Chain-Risiko. - Wegen der npm-Richtlinie „kein Unpublish bei vorhandenen Dependents“ war ein Unpublish bei fast allen betroffenen Paketen unmöglich.
- Für das Entfernen der Tarballs auf Registry-Seite musste man sich auf npm Security verlassen, wodurch die bösartigen Tarballs noch mehrere Stunden installierbar blieben.
- Die Liste von 7 Maintainers im npm-Scope bedeutet 7 separate Ziele für Credential Theft bei identischem Blast Radius.
- Beim OIDC-Trusted-Publisher-Binding gibt es keine Review pro Publish; ist es einmal eingerichtet, kann jeder Codepfad im Workflow ein veröffentlichungsfähiges Token minten.
- Eine nötige Alternative wäre der Wechsel zu kurzlebigen Classic Tokens mit manueller Review oder das Hinzufügen einer Provenance-Source-Verification, die Publishes aus unerwarteten Workflow-Schritten erkennt.
-
Wo Glück im Spiel war
- Der Angreifer wählte eine Payload, die die Tests kaputt machte, sodass der normale Publish-Schritt übersprungen wurde und kein sauberer wirkender Tarball erzeugt wurde.
- Dadurch wurde der Angriff auffällig genug, um schnell entdeckt zu werden.
- Ein vorsichtigerer Angreifer hätte ohne das Brechen der Tests noch mehrere Stunden unauffällig publizieren können.
- Der Angreifer verwendete ein öffentliches Memory-Dump-Skript mit Attribution-Kommentar wieder und schrieb keinen neuen Code, was das IOC-Matching beschleunigte.
Offene Fragen
- Es muss bestätigt werden, ob der Schritt
Setup Toolsinbundle-size.ymltatsächlichactions/cache@v5aufgerufen hat. - Zur Verifikation muss das Post-Job-Log eines
pull_request_target-Runs für PR #7378 gelesen werden; eine Beispiel-Run-ID ist25666610798. - Es muss geprüft werden, was sich im ursprünglichen PR-Head-Commit befand, bevor es durch einen Force-Push verschwand; es könnte noch im GitHub-Reflog stehen.
- Es muss bestätigt werden, ob der bösartige Commit per direktem Git-Push in den Git-Object-Store des Forks gelangte oder über eine Erstellung in der GitHub-Web-UI, die einen Audit-Log-Eintrag hinterlassen hätte.
- Es muss abgeglichen werden, ob
voicproducoesein reales Konto oder eine Sock Puppet ist, anhand des Aktivitätsverlaufs. - Es muss geprüft werden, ob auch der npm-Cache kontaminiert war, der wie 6 doppelte
linux-npm-store-*-Einträge aussieht, und ob er tatsächlich genutzt wurde. - Es muss geprüft werden, ob für den Angriff Nx Cloud erforderlich war oder ob GitHub Actions Cache allein ausgereicht hätte.
- Es muss geprüft werden, ob sich im Fork-Netzwerk von TanStack/router weitere Forks mit dem verwaisten Payload-Commit identifizieren lassen.
- Wenn andere Forks diesen Commit hosten, bleibt die Erreichbarkeit über
github:tanstack/router#79ac49ee...bestehen, was die Bereinigung erschwert. - Es ist ein Audit nötig, ob andere TanStack-Repositories wie router, query, table, form und virtual dasselbe Muster im Stil von
bundle-size.ymlverwenden. - Von npm Support muss die Zahl der Nutzer eingeholt werden, die die betroffenen Versionen während des Publish-Fensters tatsächlich heruntergeladen haben.
- Es muss geprüft werden, ob die Rechner der 7 Maintainers separat kompromittiert wurden.
- Für den bösartigen Publish wurde zwar kein npm-Token eines Maintainers verwendet, aber die Rechner der Maintainers könnten sekundäre Ziele der Self-Propagation-Logik gewesen sein.
Referenzmaterial
- TanStack/router#7383: Tracking-Issue
- GHSA-g7cv-rxg3-hmpx: GitHub Security Advisory
- The Monsters in Your Build Cache: Github Actions Cache Poisoning: Adnan Khans Forschung aus 2024 zu GitHub-Actions-Cache-Poisoning
- Keeping your GitHub Actions and workflows secure: Preventing pwn requests: Material des GitHub Security Lab zur Verhinderung von Pwn Requests
- Harden-Runner detection: tj-actions/changed-files action is compromised: verwandtes Erkennungsmaterial von StepSecurity aus März 2025
- Unpublish: npm-Unpublish-Richtlinie
- Provenance: npm-Dokumentation zu Provenance
- GHSA-g7cv-rxg3-hmpx: GitHub Security Advisory mit der vollständigen Liste der betroffenen Versionen
1 Kommentare
Hacker-News-Kommentare
Man sollte vorsichtig sein, wenn man Tokens widerruft. Es sieht so aus, als würde die Payload einen dead-man's switch unter
~/.local/bin/gh-token-monitor.shinstallieren und ihn unter Linux als systemd-Benutzerdienst sowie unter macOS alsLaunchAgent com.user.gh-token-monitorregistrierenMit dem gestohlenen Token wird alle 60 Sekunden
api.github.com/userabgefragt, und wenn der Token widerrufen wurde und ein HTTP-40x zurückkommt, wirdrm -rf ~/ausgeführthttps://github.com/TanStack/router/issues/7383#issuecomment-...
Die Softwarewelt dürfte in den nächsten fünf Jahren wirklich rau werden, und air-gapped Systeme könnten sehr wichtig werden
Auch das npm-Paket
@mistralai/mistralaiwurde als Teil dieses Wurms kompromittierthttps://github.com/mistralai/client-ts/issues/217
Inzwischen wurde es aus dem npm-Registry entfernt
Leider scheint das ein Beleg dafür zu sein, dass Trusted Publishing allein nicht ausreicht, um sicher aus CI heraus zu veröffentlichen. Mit einem Angreifer innerhalb der CI-Pipeline oder gestohlenen Repository-Admin-Rechten lässt sich leicht veröffentlichen
Das ist keine neue Information, und Trusted Publishing wurde auch nicht dafür entworfen, das zu garantieren, aber wenn man von lokalem Deployment mit Zwei-Faktor-Authentifizierung auf Trusted Publishing umstellt, entsteht dieser Angriffsweg über kompromittierte CI. Der zweite Faktor, der beim lokalen Arbeiten
npm publishverhindert hätte, fällt damit wegNach dem bisherigen Verlauf hat der Angreifer die CI/CD-Pipeline übernommen und konnte die Veröffentlichung abschließen, weil bei
npm publishkein zweiter Faktor vorhanden war, indem er den OIDC-Token gestohlen hat. Interessant, aber getrennt davon scheint der eigentliche Deployment-Job fehlgeschlagen zu sein, während die Payload im bösartigen Commit sich mit dem OIDC-Token des Workflows selbst veröffentlichen konnteWünschenswert wäre, das Trusted-Publisher-Modell ohne langlebige Tokens beizubehalten, aber für CI-Deployments dennoch einen zweiten Faktor außerhalb von GitHub zu haben. Es braucht also ein stufenweises Deployment, bei dem jemand auf npm-Seite das Artefakt per Zwei-Faktor-Authentifizierung tatsächlich in den öffentlichen Zustand überführt
Wenn Deployment ausschließlich innerhalb des GitHub-Vertrauensmodells möglich ist, kann jeder, der ein Repository-Admin-Token stiehlt oder bösartigen Code in die Pipeline bringt, die Veröffentlichung leicht abschließen. Mit einem echten zweiten Faktor außerhalb des GitHub-Kontexts kann man zwar das Repository beschädigen oder Malware einschleusen, aber ohne den zweiten Faktor für die Registry nicht veröffentlichen
Postmortem: https://tanstack.com/blog/npm-supply-chain-compromise-postmo...
Ich frage mich, ob es Belege dafür gibt, dass man Unterpakete, die TanStack-Pakete heruntergezogen oder eingebunden haben könnten, als sicher betrachten kann
postinstall-Skripte sind fatal. Alle sollten pnpm verwenden
Es ist absurd, dass ein „verwaister“ Commit, der in einen FORK gepusht wurde, beim npm-Client so etwas auslösen kann. Ich finde, auch GitHub trägt hier große Verantwortung. Dass Commits aus bösartigen Forks über GitHubs gemeinsamen Objektspeicher unter einer URI erreichbar sind, die nicht von einem legitimen Repository zu unterscheiden ist, ist ein völlig irrsinniges Design
Als ich es zuerst gelesen habe, dachte ich, das Wort „fork“ sei falsch verwendet worden und gemeint sei eigentlich ein Branch des offiziellen Repositorys. Ich dachte, das könne unmöglich echt sein, aber meine Güte
https://tanstack.com/blog/npm-supply-chain-compromise-postmo...
TanStack hat gerade ein Postmortem zu diesem Vorfall veröffentlicht
Das ist eine Erinnerung daran, die npm-Umgebung sicher zu konfigurieren
https://gajus.com/blog/3-pnpm-settings-to-protect-yourself-f...
Schon mit ein paar Einstellungen lassen sich große Probleme vermeiden
allow-git=none: https://github.blog/changelog/2026-02-18-npm-bulk-trusted-pu...min-release-age. 2) Aus irgendeinem Grund wurde sie in Tagen statt in Minuten umgesetzt: https://docs.npmjs.com/cli/v11/using-npm/config#min-release-...Ich halte den Bereich der Abhängigkeitsmanager für völlig unnötig fragmentiert
Wenn Versionsabhängigkeiten wie
^1.0.0oder sogar"*"verwendet werden, sollte man nicht weiter lesen, sondern sofort auf sichere Versionen pinnenIch habe das hastig mit Claude gebaut, um die Ausbreitung einzudämmen. Natürlich sollte man es selbst prüfen, aber es scannt, ob die erwähnten kompromittierten Pakete auf der Maschine vorhanden sind: https://github.com/PaulSinghDev/tanstack-shai-hulud-fix
Es wirkt inzwischen so, als wären wir an dem Punkt angekommen, an dem alle ihre Projekte in eigenen VMs ausführen sollten
Wenn man sich die jüngsten lokalen Privilege-Escalation-Schwachstellen ansieht, reicht Docker allein definitiv nicht aus. Container wurden schließlich auch nicht als primäre Sicherheitsgrenze entworfen
Wenn es weitere Cloud-Dienste gibt, auf die man im Container zugreifen muss, wird dieser Credential-Stealer sie ebenfalls abgreifen. Trotzdem verkleinert das immerhin den Blast Radius und ist damit wenigstens eine Verbesserung
Wow, schon wieder ein riesiges Paket. Ich poste erneut den öffentlichen Hinweis, den ich nach der Kompromittierung von Axios und LiteLLM gepostet hatte. Das gilt auch für Lifecycle-Skripte
npm/bun/pnpm/uv unterstützen inzwischen alle eine Einstellung für das Mindestalter von Paket-Releases. In
~/.npmrchabe ich außerdemignore-scripts=truegesetzt, und nach der Analyse hätte allein das die Schwachstelle entschärfen können. bun und pnpm führen Lifecycle-Skripte standardmäßig nicht ausSo lässt sich global ein Mindestalter von 7 Tagen setzen
~/.config/uv/uv.tomlexclude-newer = "7 days"~/.npmrcmin-release-age=7 # daysignore-scripts=true~/Library/Preferences/pnpm/rcminimum-release-age=10080 # minutes~/.bunfig.toml[install]minimumReleaseAge = 604800 # secondsWenn man die globale Einstellung überschreiben muss, kann man CLI-Flags verwenden
npm install --min-release-age 0pnpm add --minimum-release-age 0uv add --exclude-newer "0 days"bun add --minimum-release-age 0Noch ein Punkt: Es scheint Bedenken zu geben, dass eine breit angelegte Einführung von Wartezeiten für Abhängigkeiten dazu führt, dass Schwachstellen später entdeckt werden, oder dass solche Wartezeiten eine Art Trittbrettfahrerei sind. Dem stimme ich nicht zu. Was man gegen Wartezeiten für Abhängigkeiten eintauscht, ist Zeitpräferenz, und es wird immer Menschen geben, deren Zeitpräferenz höher ist als meine
0: https://news.ycombinator.com/item?id=47582220
1: https://news.ycombinator.com/item?id=47513932
Um unerwartete Änderungen zu vermeiden, kann man
pnpm install --frozen-lockfileverwenden. Man sollte außerdem im Hinterkopf behalten, dass man ohne gesetztesmin-release-ageauch über transitive Abhängigkeiten kompromittierte Pakete hereinziehen kann. Wenn möglich, ist es auch sinnvoll, die Version des Paketmanagers festzupinnen