Quelqu'un a enregistré le tanstack nom sur npm, a créé un SDK de lecteur vidéo qu'ils ont appelé « TanStack Player », et a publié aujourd'hui quatre versions successives conçues pour exfiltrer vos fichiers d'environnement dès que vous exécutez npm install.
Le véritable TanStack, le créateur de TanStack Query, TanStack Table, TanStack Router, tous ces @tanstack/* packages avec des millions de téléchargements hebdomadaires, n'a rien à voir avec cela. L'attaquant a simplement récupéré le nom non scopé, l'a rendu crédible et a attendu.
Aujourd'hui à 17h08 UTC, ils ont déployé la charge utile.
Ce qui s'est passé
Entre 17h08 et 17h35 UTC le 29 avril 2026, quatre nouvelles versions du tanstack package npm ont été publiées : 2.0.4, 2.0.5, 2.0.6 et 2.0.7. Les quatre contiennent un post-installation hook qui se déclenche automatiquement lors de l'installation du package.
Avant aujourd'hui, tanstack@2.0.3 (publié en mars) n'avait pas de post-installation hook. C'était un package propre, sans appels réseau. Mais cela a changé aujourd'hui.
Le postinstall.cjs script lit les fichiers d'environnement depuis le répertoire de travail du développeur et envoie leur contenu à un endpoint de webhook Svix contrôlé par l'attaquant. Aucune invite. Aucun affichage visible dans la plupart des versions. Il se déclenche et se termine simplement.
Le package comptait environ 19 830 téléchargements au cours du dernier mois avant le début de cette campagne.
La charge utile
Le script est simple. Lors de l'installation, il lit les fichiers locaux et les envoie via POST au format JSON à cet endpoint :
https://api.svix.com/ingest/api/v1/source/src_3387PLMB2uhXOBe3Q8sHu/in/3j2jokvbaF4WWdngv8zBbk
Svix est une entreprise légitime de webhooks-as-a-service. L'attaquant utilise son produit "Ingest" comme relais d'exfiltration, acheminant les données volées via un tiers de confiance pour contourner le blocage au niveau du réseau.
La charge utile comprend le contenu des fichiers ainsi que les métadonnées système :
{
"package": "tanstack",
"version": "2.0.x",
"event": "postinstall",
"readme": "<contents of .env>",
"agents": "<contents of .env.local>",
"timestamp": "...",
"node": "v22.x.x",
"platform": "linux",
"arch": "x64"
}Les noms des champs (readme, agents) sont une diversion. 🪄 Ce qui est réellement envoyé est votre .env et .env.local.
Quatre versions, 27 minutes, un attaquant testant en direct
L'historique des versions est la partie la plus intéressante de cet incident. L'attaquant a publié quatre versions en moins d'une demi-heure, itérant visiblement sur sa charge utile entre chaque push.
2.0.4 (17:08) : Cibles .env et .env.local. La vérification de l'opt-out (TANSTACK_TELEMETRY_OPT_OUT) est commentée, ce qui signifie qu'il n'y a pas d'échappatoire. Inclut un fichier en double postinstall.js qui n'apparaît dans aucune autre version. Importe le http module mais ne l'utilise jamais.
2.0.5 (17:11, trois minutes plus tard) : Modifie les fichiers cibles en README.md et AGENTS.md. Réactive également le mécanisme d'opt-out. Cela ressemble à un bref détour — soit pour tester si le webhook recevait des données, soit une tentative de rendre le hook plus inoffensif avant de revenir en arrière. README.md n'est pas un fichier de credentials.
2.0.6 (17:26) : La version dangereuse. Abandonne complètement les chemins de fichiers ciblés et les remplace par un balayage de répertoire :
function collectEnvFiles() {
const allFiles = fs.readdirSync(rootDir);
const matches = allFiles.filter(
(f) => f === ".env" || f.startsWith(".env.")
);
for (const file of matches) {
envFiles[file] = fs.readFileSync(path.join(rootDir, file), "utf-8");
}
return envFiles;
}Cela capture tout : .env, .env.local, .env.production, .env.staging, .env.development. Tout est envoyé en un seul POST. La sortie console est complètement supprimée. L'opt-out est à nouveau commenté.
2.0.7 (17:35) : Revient au .env + .env.local ciblage, garde la sortie console commentée. Ajoute une curieuse dépendance auto-référentielle "tanstack": "^2.0.6" dans son propre package.json. Que ce soit une erreur ou que cela serve un but précis n'est pas clair.
Ce que l'on observe dans cet historique des versions est un débogage en direct. L'attaquant a ajusté son ciblage, testé son récepteur et optimisé pour la discrétion, tout cela pendant que le package était publiquement disponible et installable.
L'angle du name squatting
Le @tanstack organisation publie certaines des bibliothèques JavaScript les plus utilisées sur npm : TanStack Query enregistre à lui seul environ 8 millions de téléchargements par semaine. L' tanstack nom non scopé est resté disponible séparément depuis décembre 2024.
Un développeur exécutant npm install tanstack au lieu de npm install @tanstack/query n'obtient pas ce qu'il attend. Il obtient ceci.
Le README du package est soigné. Il contient un badge de parrainage, des badges de téléchargement npm, un tableau comparatif des fonctionnalités, des exemples de code. Il se présente comme un produit réel. La présentation est suffisamment convaincante pour qu'un coup d'œil rapide ne soulève aucun soupçon.
Ce qui est dérobé
Dans un projet JavaScript typique, .env les fichiers contiennent :
- Clés d'accès et secrets AWS
- Jetons d'accès personnels GitHub
- Jetons de publication npm
- Chaînes de connexion de base de données
- Clés API Stripe, Twilio, Resend, SendGrid
- Clés API OpenAI, Anthropic et autres LLM
- Secrets client OAuth
- Toute autre information d'identification tierce configurée localement
Si vous avez un .env.production fichier n'importe où près de votre répertoire de travail (la version 2.0.6 l'aurait trouvé), ce sont des identifiants de production remis à un attaquant lors de l'installation.
Correction et détection
Étape 1 : Vérifiez si vous avez été affecté
Vérifiez vos fichiers de verrouillage et l'historique d'installation pour l'une de ces versions de package :
# Vérifier package-lock.json
grep -r "tanstack" package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null
# Vérifier node_modules
ls node_modules/tanstack/package.json 2>/dev/null && cat node_modules/tanstack/package.json | grep '"version"'Versions affectées : 2.0.4, 2.0.5, 2.0.6, 2.0.7. Si l'une de ces versions apparaît dans un fichier de verrouillage, considérez vos fichiers d'environnement comme compromis.
Étape 2 : Si vous avez été affecté
Considérez que tout .env fichier présent dans le répertoire de travail au moment de l'installation a été exfiltré. Procédez immédiatement à la rotation de :
- Clés d'accès et secrets AWS (vérifiez CloudTrail pour les appels d'API non autorisés)
- Tokens GitHub avec portée de dépôt ou d'organisation
- Tokens npm — révoquez-les sur npmjs.com/settings et réémettez-les
- Toutes les informations d'identification de base de données présentes dans
.env - Toutes les clés API tierces dans les fichiers affectés
Pour les environnements CI : le postinstall se déclenche pendant npm ci également. Si votre pipeline CI a installé ce package, faites pivoter tous les secrets injectés dans l'environnement de ce pipeline. Vérifiez les journaux de tâches de votre fournisseur CI pour l'étape d'installation aux alentours du moment de la compromission.
Pour les machines de développeurs : il s'agit d'une exfiltration de données persistante, et non d'une attaque en mémoire. Les fichiers ont été lus et envoyés. Il n'y a pas de binaires déposés ni de mécanismes de persistance à nettoyer, mais vos identifiants sont déjà compromis.
Recherchez le trafic HTTPS sortant vers api.svix.com dans vos journaux réseau aux alentours du moment de l'installation. La requête POST proviendrait du runner CI ou de la machine de développement exécutant l'installation.
Étape 3 : Détectez-le avec Aikido
Si vous êtes un utilisateur Aikido, vérifiez votre flux central et filtrez les problèmes de malware. La vulnérabilité sera signalée comme un problème critique 100/100 dans le flux. Conseil : Aikido réanalyse vos dépôts chaque nuit, mais nous vous recommandons également de déclencher une réanalyse complète.
Si vous n'êtes pas encore un utilisateur Aikido, créez un compte et connectez vos dépôts. Notre couverture propriétaire des malwares est incluse dans le plan gratuit (aucune carte de crédit requise).
Étape 4 : Protection future (SafeChain)
Pour une protection future, envisagez d'utiliser Aikido SafeChain (open source), un wrapper sécurisé pour npm, npx, yarn, pnpm et pnpx. SafeChain s'intègre à vos workflows actuels, interceptant les commandes d'installation de packages et vérifiant les packages contre les malwares via Aikido Intel avant l'installation. Stoppez les menaces avant qu'elles n'atteignent votre machine.
IOCs
tanstack@2.0.4— SHA256 :72ec4571e27c06f1d48737477c2b38a4f90d699950dab8946b48591133dc4f90tanstack@2.0.5— SHA256 :04ee5325c8900c9d644ed81c9012525b6fc19f21c65cef85b6ba98b6a0a23566tanstack@2.0.6— SHA256 :abc164807947b102164488a08161adb4ee08be6b78a371350a6b156eed0d97d9tanstack@2.0.7— SHA256 :7bb84e6ba893248814cd3bac70b7bdc115740fba9e13419940c73460cbcd7b6f- Point de terminaison d'exfiltration :
hxxps://api.svix[.]com/ingest/api/v1/source/src_3387PLMB2uhXOBe3Q8sHu/in/3j2jokvbaF4WWdngv8zBbk - ID de source Svix :
src_3387PLMB2uhXOBe3Q8sHu - Compte de mainteneur npm :
sh20raj
Fermeture
Cette attaque nous rappelle à quel point il suffit de peu pour transformer une configuration de name-squatting en un collecteur d'identifiants actif. L'attaquant n'a pas eu besoin de compromettre un mainteneur, de hameçonner un système CI ou d'exploiter une vulnérabilité. Il a enregistré un package au nom plausible, ajouté un script post-installation d'une seule page et attendu que les installations se multiplient.
Le modèle d'itération en quatre versions est à noter. Ce n'était pas un déploiement unique. L'attaquant était présent, observait et ajustait sa charge utile en temps réel. C'est quelqu'un qui sait ce qu'il fait et qui optimisait spécifiquement la couverture des identifiants.
Chaque .env le fichier dans votre projet est une cible. Tout package avec un hook post-installation peut les lire. Le registre npm donne cette capacité à chaque éditeur par défaut.

