🔍 Contexte
Le 11 mai 2026, TanStack a publié un post-mortem détaillé d’une compromission de chaîne d’approvisionnement npm survenue entre 19:20 et 19:26 UTC. L’incident a affecté 42 packages @tanstack/* avec 84 versions malveillantes publiées via un enchaînement de trois vulnérabilités dans le pipeline GitHub Actions.
⚙️ Vecteur d’attaque — Trois vulnérabilités chaînées
1. Pattern « Pwn Request » via pull_request_target
Le workflow bundle-size.yml utilisait le déclencheur pull_request_target et effectuait un checkout du code de la PR fork, permettant l’exécution de code non approuvé dans le contexte du dépôt de base.
2. Empoisonnement du cache GitHub Actions
Le payload malveillant vite_setup.mjs (~30 000 lignes) a écrit dans le répertoire pnpm-store sous la clé exacte que release.yml utiliserait lors du prochain push sur main (Linux-pnpm-store-6f9233a50def742c09fde54f56553d6b449a535adf87d4083690539f49ae4da11). Le cache empoisonné (1,1 Go) a persisté après fermeture de la PR.
3. Extraction mémoire du token OIDC
Lors de l’exécution de release.yml sur main, les binaires malveillants restaurés depuis le cache ont localisé le processus GitHub Actions Runner.Worker via /proc/*/cmdline, lu /proc/<pid>/maps et /proc/<pid>/mem pour extraire le token OIDC en mémoire, puis l’ont utilisé pour publier directement sur registry.npmjs.org — contournant entièrement l’étape Publish Packages du workflow légitime.
🦠 Comportement du malware
Le script router_init.js (~2,3 Mo, obfusqué), exécuté lors du npm install / pnpm install / yarn install, effectuait les actions suivantes :
- Collecte de credentials : AWS IMDS/Secrets Manager, GCP metadata, tokens Kubernetes, Vault,
~/.npmrc, tokens GitHub, clés SSH privées - Exfiltration via le réseau Session/Oxen (
filev2.getsession.org,seed{1,2,3}.getsession.org) — chiffré de bout en bout - Auto-propagation : énumération des packages maintenus par la victime via l’API npm et republication avec la même injection
📅 Chronologie clé
- 2026-05-10 17:16 : Création du fork
github.com/zblgg/configuration(renommé pour éviter les recherches) - 2026-05-10 23:29 : Commit malveillant
65bf499davec identité forgéeclaude <claude@users.noreply.github.com> - 2026-05-11 11:11 : Exécution de
vite_setup.mjsvia le jobbenchmark-pr - 2026-05-11 11:29 : Cache empoisonné sauvegardé
- 2026-05-11 19:20–19:26 : Publication des 84 versions malveillantes via deux runs de
release.yml - 2026-05-11 ~19:50 : Détection externe par le chercheur
ashishkurmi(StepSecurity) ~20 minutes après la publication
🎯 Impact
- 42 packages @tanstack/* affectés (familles @tanstack/router, @tanstack/history, @tanstack/start-*, etc.)
- Familles confirmées non affectées : @tanstack/query*, @tanstack/table*, @tanstack/form*, @tanstack/virtual*, @tanstack/store, @tanstack/start
- Aucun token npm volé ; le workflow de publication légitime n’a pas été compromis directement
- Toute machine ayant installé une version affectée le 2026-05-11 doit être considérée comme potentiellement compromise
📄 Type d’article
Post-mortem technique publié par l’équipe TanStack, visant à documenter précisément le vecteur d’attaque, la chronologie, les IOCs et les leçons tirées pour la communauté open source et les équipes de sécurité.
🧠 TTPs et IOCs détectés
Acteurs de menace
- zblgg (unknown) —
- voicproducoes (unknown) —
TTP
- T1195.001 — Supply Chain Compromise: Compromise Software Dependencies and Development Tools (Initial Access)
- T1059.007 — Command and Scripting Interpreter: JavaScript (Execution)
- T1552.001 — Unsecured Credentials: Credentials In Files (Credential Access)
- T1552.005 — Unsecured Credentials: Cloud Instance Metadata API (Credential Access)
- T1003 — OS Credential Dumping (Credential Access)
- T1567 — Exfiltration Over Web Service (Exfiltration)
- T1036.005 — Masquerading: Match Legitimate Name or Location (Defense Evasion)
- T1072 — Software Deployment Tools (Execution)
- T1176 — Browser Extensions (Persistence)
- T1608.001 — Stage Capabilities: Upload Malware (Resource Development)
IOC
- Domaines :
filev2.getsession.org— VT · URLhaus · ThreatFox - Domaines :
seed1.getsession.org— VT · URLhaus · ThreatFox - Domaines :
seed2.getsession.org— VT · URLhaus · ThreatFox - Domaines :
seed3.getsession.org— VT · URLhaus · ThreatFox - Domaines :
litter.catbox.moe— VT · URLhaus · ThreatFox - URLs :
https://litter.catbox.moe/h8nc9u.js— URLhaus - URLs :
https://litter.catbox.moe/7rrc6l.mjs— URLhaus - Emails :
claude@users.noreply.github.com - Fichiers :
router_init.js - Fichiers :
vite_setup.mjs
Malware / Outils
- router_init.js (stealer)
- vite_setup.mjs (loader)
🟡 Indice de vérification factuelle : 63/100 (moyenne)
- ⬜ tanstack.com — source non référencée (0pts)
- ✅ 17413 chars — texte complet (fulltext extrait) (15pts)
- ✅ 10 IOCs (IPs/domaines/CVEs) (10pts)
- ✅ 1/5 IOC(s) confirmé(s) (ThreatFox, URLhaus, VirusTotal) (8pts)
- ✅ 10 TTPs MITRE identifiées (15pts)
- ✅ date extraite du HTML source (10pts)
- ✅ acteur(s) identifié(s) : zblgg, voicproducoes (5pts)
- ⬜ pas de CVE à vérifier (0pts)
IOCs confirmés externellement :
filev2.getsession.org(domain) → VT (17/92 détections) + ThreatFox (Unknown malware)
🔗 Source originale : https://tanstack.com/blog/npm-supply-chain-compromise-postmortem