Quelqu'un a enregistré le tanstack présents sur npm, ont développé un SDK de lecteur vidéo baptisé « TanStack Player » et ont publié aujourd’hui quatre versions successives conçues pour extraire les fichiers de votre environnement dès que vous les exécutez npm install.
Le véritable TanStack, qui regroupe TanStack Query, TanStack Table, TanStack Router, et tous ces @tanstack/* Le fait que ces applications soient téléchargées des millions de fois chaque semaine n'a rien à voir avec cela. L'attaquant s'est simplement emparé du nom sans espace, l'a habillé de manière convaincante, puis a attendu.
Aujourd'hui, à 17 h 08 UTC, ils ont déployé la charge utile.
Que s'est-il passé ?
Entre 17 h 08 et 17 h 35 UTC, le 29 avril 2026, quatre nouvelles versions du tanstack Les versions suivantes du paquet npm ont été publiées : 2.0.4, 2.0.5, 2.0.6 et 2.0.7. Ces quatre versions contiennent une post-installation un hook qui se déclenche automatiquement lors de l'installation du paquet.
Jusqu'à aujourd'hui, tanstack@2.0.3 (publié en mars) ne comportait aucune post-installation hook. C'était un package épuré, sans aucun appel réseau. Mais cela a changé aujourd'hui.
Le postinstall.cjs Le script lit les fichiers de configuration dans le répertoire de travail du développeur et transmet leur contenu à un point de terminaison Svix webhook contrôlé par un pirate. Aucune invite. Aucune sortie visible dans la plupart des versions. Il s'exécute simplement puis se ferme.
Le pack a été téléchargé environ 19 830 fois au cours du mois précédant le lancement de cette campagne.
La charge utile
Le script est simple. Lors de l'installation, il lit les fichiers locaux et les envoie via une requête POST au format JSON vers ce point de terminaison :
https://api.svix.com/ingest/api/v1/source/src_3387PLMB2uhXOBe3Q8sHu/in/3j2jokvbaF4WWdngv8zBbk
Svix est une entreprise légitime proposant des services de webhooks. Le pirate utilise son produit « Ingest » comme relais d'exfiltration, acheminant les données volées via un tiers de confiance afin de contourner les blocages au niveau du réseau.
La charge utile comprend le contenu des fichiers ainsi que les métadonnées du 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 (fichier Lisez-moi, agents) ne sont que des diversions. 🟒 Ce qui est réellement envoyé, c'est ton .env et .env.local.
Quatre versions, 27 minutes, un pirate effectuant un test en direct
L'historique des versions est l'aspect le plus intéressant de cet incident. L'attaquant a publié quatre versions en moins d'une demi-heure, modifiant visiblement sa charge utile entre chaque publication.
2.0.4 (17 h 08) : Cibles .env et .env.local. La case à cocher pour se désinscrire (TANSTACK_TELEMETRY_OPT_OUT) est commentée, ce qui signifie qu'il n'y a pas escape . Comprend un doublon postinstall.js fichier qui n'apparaît dans aucune autre version. Importe le http module, mais ne l'utilise jamais.
2.0.5 (17 h 11, trois minutes plus tard) : Modifie les fichiers cibles pour README.md et AGENTS.md. Cela réactive également le mécanisme de désactivation. Cela ressemble à un bref détour — soit pour vérifier si le webhook recevait bien des données, soit pour tenter de donner au hook un aspect plus anodin avant de revenir en arrière. README.md n'est pas un fichier d'informations d'identification.
2.0.6 (17 h 26) : La version dangereuse. Supprime complètement les chemins d'accès aux fichiers ciblés et les remplace par un balayage de répertoires :
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 couvre tout : .env, .env.local, .env.production, .env.staging, .env.development. Le tout est envoyé en une seule requête POST. L'affichage sur la console est complètement désactivé. L'option de désactivation est à nouveau mise en commentaire.
2.0.7 (17 h 35) : Retour à la version .env + .env.local le ciblage, maintient la sortie console commentée. Ajoute une dépendance autoréférentielle curieuse « tanstack » : « ^2.0.6 » dans son propre fichier package.json. On ne sait pas vraiment s'il s'agit d'une erreur ou si cela a une raison d'être.
Ce que vous observez dans cet historique des versions, c'est un débogage en temps réel. L'attaquant a ajusté sa cible, testé son programme malveillant et optimisé sa dissimulation, tout cela alors que le paquet était accessible au public et pouvait être installé.
L'angle d'accroupissement
Le @tanstack Cette organisation publie certaines des bibliothèques JavaScript les plus utilisées sur npm : à elle seule, TanStack Query enregistre environ 8 millions de téléchargements par semaine. La tanstack Le nom « unscoped » est resté à part depuis décembre 2024.
Un développeur qui exécute npm install tanstack au lieu de npm install @tanstack/query Ils n'obtiennent pas ce à quoi ils s'attendaient. Ils obtiennent ça.
Le fichier README du paquet est soigné. Il comporte un badge de parrainage, des icônes de téléchargement npm, un tableau comparatif des fonctionnalités et des exemples de code. Il se présente comme un véritable produit. La façade est suffisamment convaincante pour qu'un simple coup d'œil ne permette pas de le repérer.
Ce qui est volé
Dans un projet JavaScript classique, .env Les fichiers contiennent :
- Clés d'accès et secrets AWS
- Jeton d'accès personnel GitHub
- Jeton de publication npm
- Chaînes de connexion à la base de données
- Clés API Stripe, Twilio, Resend et SendGrid
- Clés d'API d'OpenAI, d'Anthropic et d'autres modèles de langage à grande échelle (LLM)
- Secrets de client OAuth
- Tout autre identifiant tiers configuré localement
Si vous avez un .env.production si ce fichier se trouve où que ce soit à proximité de votre répertoire de travail (la version 2.0.6 l'aurait détecté), cela revient à remettre les identifiants de production entre les mains d'un pirate dès l'installation.
Détection et remédiation
Étape 1 : Vérifiez si vous avez été concerné
Vérifiez vos fichiers de verrouillage et l'historique des installations pour voir si l'une de ces versions de paquets y figure :
# Vérifier le fichier 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 concernées : 2.0.4, 2.0.5, 2.0.6, 2.0.7. Si l'un de ces éléments apparaît dans un fichier de verrouillage, considérez que vos fichiers de configuration ont été compromis.
Étape 2 : Si vous avez été touché
Supposons que .env Le fichier présent dans le répertoire de travail au moment de l'installation a été exfiltré. Procédez immédiatement à la rotation :
- Clés d'accès et secrets AWS (vérifiez CloudTrail pour détecter les appels API non autorisés)
- Jeton GitHub avec portée « dépôt » ou « organisation »
- Jeton npm — révoquer sur npmjs.com/settings et en générer un nouveau
- Toutes les informations d'identification de base de données présentes dans
.env - Toutes les clés API tierces contenues dans les fichiers concernés
Pour les environnements CI : le script post-installation s'exécute pendant npm ci ainsi. Si votre pipeline CI a installé ce paquet, procédez à la rotation de tous les secrets injectés dans l'environnement de ce pipeline. Consultez les journaux des tâches de votre fournisseur de CI pour repérer l'étape d'installation correspondant à la période où la compromission a eu lieu.
Pour les machines des développeurs : il s'agit d'une exfiltration persistante de données, et non d'une attaque en mémoire. Les fichiers ont été lus et envoyés. Il n'y a pas de fichiers binaires déposés ni de mécanismes de persistance à supprimer, mais vos identifiants ont déjà été compromis.
Recherchez le trafic HTTPS sortant vers api.svix.com dans vos journaux réseau au moment de l'installation. La requête POST aurait été envoyée par le serveur d'exécution CI ou par la machine du développeur chargée de 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 pour l'avenir (SafeChain)
Pour vous protéger à l'avenir, pensez à utiliser Aikido (open source), une interface sécurisée pour npm, npx, yarn, pnpm et pnpx. SafeChain s'intègre à vos flux de travail actuels : il intercepte les commandes d'installation de paquets et vérifie, avant l'installation, que ceux-ci ne contiennent pas de logiciels malveillants en les comparant aux Aikido . Bloquez 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 d'extrémité d'exfiltration :
hxxps://api.svix[.]com/ingest/api/v1/source/src_3387PLMB2uhXOBe3Q8sHu/in/3j2jokvbaF4WWdngv8zBbk - Identifiant source Svix :
src_3387PLMB2uhXOBe3Q8sHu - Compte de responsable npm :
sh20raj
Clôture
Cette attaque nous rappelle à quel point il suffit de peu pour transformer un système de détournement de nom en un outil actif de collecte d'identifiants. L'attaquant n'a pas eu besoin de compromettre un responsable de maintenance, de pirater un système d'intégration continue (CI) ni d'exploiter une faille de sécurité. Il a simplement enregistré un paquet au nom plausible, y a ajouté un script post-installation d'une page, puis a attendu que les installations se multiplient.
Il convient de noter le schéma d'itération en quatre étapes. Il ne s'agissait pas d'un déploiement ponctuel. L'attaquant était présent, observait et adaptait sa charge utile en temps réel. C'est quelqu'un qui sait ce qu'il fait et qui cherchait spécifiquement à optimiser la couverture des identifiants.
Chaque .env Le fichier de votre projet est une cible. Tout paquet doté d'un hook postinstall peut les lire. Le registre npm offre cette possibilité à tous les éditeurs par défaut.

