
Vérificateur d'IOC pour l'attaque sur la chaîne d'approvisionnement npm TanStack/Mini Shai-Hulud (CVE-2026-45321)
curl -fsSL https://raw.githubusercontent.com/nkopylov/tanscript-exploit-check/main/check-tanstack-exploit.sh | bash
Ou clonez et exécutez localement :
git clone https://github.com/nkopylov/tanscript-exploit-check.git
cd tanscript-exploit-check
./check-tanstack-exploit.sh [project_dir ...]
Ce vérificateur couvre deux vagues de la campagne d'attaque de la chaîne d'approvisionnement Mini Shai-Hulud menée par TeamPCP :
Le 11 mai 2026 (19:20-19:26 UTC), un attaquant a publié 84 versions malveillantes sur 42 paquets npm @tanstack/* en une fenêtre de 6 minutes. L'attaque a également touché des paquets de Mistral AI, UiPath, OpenSearch et d'autres — plus de 170 paquets au total sur npm et PyPI.
Aucun identifiant de mainteneur n'a été volé. L'attaquant a exploité la chaîne de confiance CI/CD elle-même via une attaque en 3 étapes :
pull_request_target — Un fork GitHub jetable a ouvert une PR qui exécutait du code attaquant dans le contexte de sécurité du dépôt de baseLe 19 mai 2026 (01:39-02:06 UTC), le compte npm compromis atool ([email protected]) a publié 637 versions malveillantes sur 314 paquets en deux vagues automatisées. Les cibles à fort impact incluent :
size-sensor (4,2 M de téléchargements/mois)echarts-for-react (3,8 M de téléchargements/mois)@antv/scale (2,2 M de téléchargements/mois)timeago.js (1,15 M de téléchargements/mois)@antv/* et autresCette vague utilisait une charge utile basée sur Bun (498 Ko index.js) déclenchée via "preinstall": "bun run index.js", avec une charge utile de deuxième niveau cachée dans des commits imposteurs poussés vers le dépôt GitHub antvis/G2 via l'exploit de partage d'objet fork.
Les deux vagues utilisent la même famille d'outils « Mini Shai-Hulud » :
gh-token-monitor (Vague 1) et kitty-monitor (Vague 2) via LaunchAgent/systemd ; hooks dans .claude/settings.json et .vscode/tasks.jsontoJSON(secrets), échange de jetons OIDC npmrm -rf ~/ si le jeton GitHub est révoqué alors que le démon est actiffiredalazer, commandes signées RSA-PSSSeuls @tanstack/router* et @tanstack/start* ont été concernés. NON concernés : @tanstack/query*, @tanstack/table*, @tanstack/form*, @tanstack/virtual*, @tanstack/store.
Voir l'avis complet pour les 42 paquets.
Tous les paquets publiés par l'utilisateur npm atool ([email protected]) ont reçu des versions malveillantes le 19 mai 2026. Les paquets à fort impact incluent :
| Paquet | Téléchargements mensuels |
|---|---|
size-sensor | 4,2 M |
echarts-for-react | 3,8 M |
@antv/scale | 2,2 M |
Plus 310+ paquets principalement dans le scope @antv/* (@antv/g2, @antv/g6, @antv/l7, @antv/s2, @antv/x6, @antv/f2, etc.), ai-figure, timeago-react, jest-canvas-mock, jest-date-mock, et d'autres.
Voir l'article SafeDep pour la liste complète.
CRITIQUE : Désactivez l'interrupteur de sécurité AVANT de révoquer un quelconque jeton. Le logiciel malveillant efface
$HOMEsi les jetons sont révoqués alors que le démon est actif.
gh-token-monitor ET kitty-monitor) et supprimez les services LaunchAgent/systemd.claude/router_runtime.js, .vscode/setup.mjs, ~/.local/share/kitty/cat.py, /var/tmp/.gh_update_state, etc.)node_modules et les lockfiles, réinstallez avec --ignore-scriptsapi.masscan.cloud, filev2.getsession.org, git-tanstack.com, t.m-kosche.com)Copiez-collez ces invites dans votre agent de codage IA (Claude Code, Cursor, Cline/OpenClaw, Windsurf, Hermes, etc.) pour durcir votre projet contre les attaques de la chaîne d'approvisionnement comme celle-ci.
Durcissez la configuration npm de ce projet contre les attaques de la chaîne d'approvisionnement. Effectuez les actions suivantes :
Épinglez les versions exactes : Supprimez tous les préfixes
^et~de chaque dépendance danspackage.jsonafin quenpm installne récupère jamais silencieusement une version nouvellement publiée.Désactivez les scripts postinstall par défaut : Ajoutez
ignore-scripts=truedans.npmrc. Ajoutez ensuite un script"preinstall"explicite danspackage.jsonqui n'exécute que les scripts de cycle de vie connus et sûrs dont ce projet a réellement besoin (le cas échéant).Imposez des installations basées uniquement sur le lockfile en CI : Assurez-vous que la CI utilise
npm ci(pasnpm install). S'il existe un fichier de configuration CI, vérifiez-le. Sinon, notez-le comme une étape manuelle.Ajoutez la vérification de provenance : Ajoutez
npm audit signaturescomme étape dans le pipeline CI et comme hook git pre-push.
Auditez et durcissez la configuration de l'agent de codage IA de ce projet contre les attaques par injection de la chaîne d'approvisionnement (comme la campagne TanStack/Mini Shai-Hulud qui a injecté des hooks malveillants dans
.claude/settings.jsonet.vscode/tasks.json). Effectuez les actions suivantes :Claude Code (
.claude/) :
- Examinez
.claude/settings.jsonet.claude/settings.local.jsonpour toute entréehooksqui exécute des commandes shell. Signalez tout ce qui exécute des fichiers.js,.mjsou.sh— surtout s'ils proviennent de.claude/,.vscode/ounode_modules/.- Supprimez tous les hooks que vous ne pouvez pas rattacher à un usage légitime et créé par l'utilisateur.
Auditez et durcissez la configuration GitHub Actions de ce dépôt contre les attaques CI/CD de la chaîne d'approvisionnement. Effectuez les actions suivantes :
Supprimez ou refactorez tout déclencheur
pull_request_target— ceux-ci exécutent le code du workflow dans le contexte du dépôt de base avec accès aux secrets, même lorsqu'ils sont déclenchés par un fork. Remplacez parpull_request+ un workflow séparé avec validation d'approbation si nécessaire.Épinglez toutes les actions tierces à des SHA de commit complets (pas des tags ou branches). Par exemple, remplacez
actions/checkout@v4paractions/checkout@<sha-complet>. Ajoutez un commentaire avec le tag pour la lisibilité.Appliquez le principe du moindre privilège à chaque workflow. Ajoutez des blocs
permissions:explicites. La plupart des workflows n'ont besoin que decontents: read. Les workflows de publication ont besoin deid-token: write— et rien d'autre.Restreignez la portée du cache : Si vous utilisez
actions/cache, assurez-vous que les clés de cache sont limitées à la branche pour éviter l'empoisonnement inter-branches. Ajoutezrestore-keysavec précaution — ne restaurez pas les caches de branches non fiables.
MIT
| # | Vérification | Description |
|---|
| 1 | Interrupteur de sécurité | Démons de persistance : gh-token-monitor (Vague 1), kitty-monitor (Vague 2) |
| 2 | Processus malveillants | Noms de processus attaquants connus (les deux vagues) |
| 3 | Fichiers de charge utile | Fichiers malveillants connus par nom et hachage SHA-256 (4 hachages) |
| 4 | Hooks Claude Code | Hooks injectés dans .claude/settings.json + heuristique générique SessionStart |
| 5 | Tâches VS Code | Tâches injectées dans .vscode/tasks.json + heuristique générique runOn: folderOpen |
| 6 | GitHub Actions | toJSON(secrets) dans tout workflow + avertissement pull_request_target |
| 7 | Lockfiles npm | Versions de paquets compromises dans les lockfiles |
| 8 | optionalDependencies | @tanstack/setup et @antv/setup malveillants + 4 SHA de commits imposteurs |
| 9 | Connexions réseau | Connexions actives vers l'infrastructure C2 (5 domaines/IP) |
| 10 | Cache DNS | Résolution antérieure de domaines attaquants (4 domaines) |
| 11 | Branches Git | Modèle de nommage de branches attaquantes inspiré de Dune |
| 12 | Scripts de cycle de vie | Heuristique : bun run dans preinstall/postinstall (paquets installés) |
| 13 | C2 par dépôt mort | Mot‑clé firedalazer et marqueurs « Shai-Hulud » dans l'historique git |
| 14 | Dépendances GitHub | Heuristique : dépendances github: épinglées à un SHA de commit dans optionalDeps |
| Paquet | Versions malveillantes | Première version sûre |
|---|
@tanstack/react-router | 1.169.5, 1.169.8 | 1.169.9 |
@tanstack/router-core | 1.169.5, 1.169.8 | 1.169.9 |
@tanstack/vue-router | 1.169.5, 1.169.8 | 1.169.9 |
@tanstack/solid-router | 1.169.5, 1.169.8 | 1.169.9 |
@tanstack/react-start | 1.167.68, 1.167.71 | 1.167.72 |
@tanstack/router-plugin | 1.167.38, 1.167.41 | 1.167.42 |
timeago.js | 1,15 M |
Créez un script de politique de mise à jour : Créez un scripts/safe-update.sh qui :
npm view <pkg> time --json)npm install <pkg>@latest --save-exactNe modifiez aucun code applicatif. Touchez uniquement les fichiers de configuration, .npmrc, les scripts package.json et la configuration CI.
.gitignore pour empêcher que .claude/settings.local.json soit commité (il doit rester local).VS Code (.vscode/) :
.vscode/tasks.json et .vscode/launch.json pour les tâches qui exécutent des scripts ou binaires inattendus.setup.mjs, router_runtime.js ou d'autres noms qui n'appartiennent pas à ce projet..vscode/extensions.json pour des extensions que vous ne reconnaissez pas.Cursor (.cursor/) :
.cursor/settings.json et tous les fichiers de règles pour des commandes ou hooks injectés..vscode/.Général :
preinstall, postinstall, prepare ou prestart dans package.json que vous n'avez pas écrits. Signalez ceux qui sont suspects..github/workflows/ pour tout workflow utilisant pull_request_target — signalez-le comme un risque de sécurité avec un commentaire expliquant pourquoi..gitignore exclut les fichiers de session de l'agent qui pourraient fuiter des identifiants (.claude/projects/, .cursor/logs/, etc.).Rapportez ce que vous avez trouvé et ce que vous avez modifié. Ne modifiez pas le code applicatif.
Ajoutez StepSecurity Harden-Runner comme première étape de chaque job : step-security/harden-runner@v2 avec egress-policy: audit (ou block si vous connaissez vos points de terminaison autorisés).
Vérifiez la présence de secrets dans les journaux du workflow : Assurez-vous qu'aucune étape du workflow n'affiche ${{ secrets.* }} ou ${{ toJSON(secrets) }} dans la sortie standard.
Rapportez toutes les modifications. Ne modifiez pas le code applicatif.