Le 4 août 2026, une attaque sophistiquée visant la chaîne d’approvisionnement logicielle, baptisée « ChainDrop », a frappé l’écosystème npm après le piratage du compte GitHub d’un responsable de maintenance des paquets open source Keyv et Cacheable, largement utilisés . Le ver auto-propagateur qui en a résulté s’est propagé à plus de 2 251 versions de 452 paquets distincts , totalisant environ 2 milliards de téléchargements mensuels, affectant des organisations telles que Deliveroo, Ornikar, OneReach, Picsart, Qlik et ServiceTitan.
Keyv est un simple magasin clé-valeur pour Node.js prenant en charge plusieurs backends, tandis que Cacheable est son framework de cache HTTP sous-jacent. Ensemble, ces paquets constituent l’infrastructure de mise en cache fondamentale de l’écosystème JavaScript. Les deux paquets sont maintenus par le même développeur, dont le compte GitHub a été compromis par l’acteur malveillant.
L’attaquant a publié la première version malveillante, keyv@6.0.0, vers 9 h 00 UTC le 4 août 2026. Ce logiciel malveillant est un descendant de la famille « Mini » Shai-Hulud; son attribution à TeamPCP reste à confirmer. Le ver s’est propagé rapidement en récupérant des jetons npm et GitHub dans des environnements compromis, puis en les utilisant pour publier d’autres versions infectées. Socket a recensé 2 251 versions infectées réparties sur 452 paquets.
La charge utile vole un large éventail de données sensibles, notamment des identifiants de cloud, des secrets CI/CD, des jetons de développeurs, des fichiers de configuration d’IA et des portefeuilles de cryptomonnaies .Elle implante également des hooks Claude Code et Visual Studio Code pour une exécution persistante au sein de l’IDE. Aucun identifiant CVE n’a été attribué à cette campagne au moment de la rédaction de cet article.
Accès initial
L’acteur malveillant a compromis le compte GitHub du responsable de Keyv, ce qui lui a donné un accès direct en écriture aux dépôts source de Keyv, Cacheable, cache-manager, flat-cache, file-entry-cache et de nombreux paquets associés au sein du monorepo du responsable.
Publication malveillante
À partir de 9 h 00 UTC, l’attaquant a introduit des charges utiles de persistance IDE dans le dépôt Keyv, puis a publié keyv@6.0.0 et les versions malveillantes suivantes. Comme les paquets ont été compilés et publiés via leurs workflows GitHub Actions légitimes, les versions compromises comportaient des informations de provenance SLSA valides, contournant ainsi les contrôles de vérification d’intégrité. Chaque paquet corrompu contenait une entrée « preinstall » : « node setup.mjs » dans son fichier package.json, ce qui provoquait l’exécution automatique du dropper avant la fin de toute installation npm.
Propagation du ver
La capacité d’auto-propagation du logiciel malveillant lui a permis d’infecter des paquets appartenant à d’autres responsables de maintenance dont les projets dépendaient d’un paquet précédemment compromis. En récupérant des jetons de publication npm valides à partir des environnements CI/CD et des postes de travail des développeurs, le ver republiait les paquets en aval en y injectant la charge utile malveillante, créant ainsi une chaîne de compromission en cascade. Ce mécanisme a permis à l’attaque de s’échapper de l’espace de noms Keyv/Cacheable d’origine et de se propager au-delà des frontières organisationnelles.
Paquets affectés
Parmi les principaux paquets compromis figuraient :
|
Nom du paquet |
Version(s) malveillante(s) concernée(s) |
Version vérifiée comme sûre / Version restaurée et propre |
|
keyv |
6.0.0 (et versions malveillantes ultérieures) |
5.6.0 |
|
flat-cache |
6.1.24 |
6.1.23 |
|
cache-entrée-fichier |
11.1.6 |
11.1.5 (ou version stable précédente) |
|
cacheable-request |
13.0.20 |
13.0.19 (ou version stable précédente) |
|
cache-manager |
7.2.10 |
7.2.9 |
|
cacheable |
2.5.1 |
2.5.0 (ou version stable antérieure) |
|
@cacheable/utils |
2.5.1 |
2.5.0 (ou version stable antérieure) |
|
@cacheable/memory |
2.2.1 |
2.2.0 (ou version stable antérieure) |
|
@cacheable/node-cache |
3.1.2 |
3.1.1 (ou version stable antérieure) |
|
@cacheable/net |
2.1.1 |
2.1.0 (ou version stable précédente) |
|
ecto |
5.0.1 |
5.0.0 (ou version stable antérieure) |
Le ver s’est ensuite propagé à des paquets au sein d’organisations telles qu’Ornikar (notamment @ornikar/eslint-config-*, @ornikar/prettier-config, @ornikar/babel-preset-* et bien d’autres), Qlik (@nebula.js/nucleus), HubSync (@hubsync/web-sdk-react) et bien d’autres encore. Une liste complète et mise à jour en continu est gérée par Wiz Research sur son dépôt GitHub public.
Important : le registre npm a évolué rapidement tout au long de l’incident. À 17 h 40 IST le 4 août, des versions antérieures non compromises ont été rétablies comme versions les plus récentes pour au moins neuf paquets essentiels, notamment keyv@5.6.0, flat-cache@6.1.23 et cache-manager@7.2.9. Les organisations doivent vérifier leur exposition en se basant sur les versions exactes des paquets enregistrées dans les fichiers de verrouillage, et non sur les balises actuelles du registre.
Analyse du logiciel malveillant
Présentation de la charge utile
Le logiciel malveillant se déploie selon une architecture en deux étapes:
Étape 1 – setup.mjs (dropper) : ce script Node.js léger sert de charge utile initiale. Il vérifie la présence du runtime JavaScript Bun et, en son absence, télécharge Bun v1.3.13 à partir des versions officielles sur GitHub. Il transfère ensuite l'exécution au bundle principal de l'infostealer avant de supprimer le répertoire temporaire du runtime afin de réduire les traces laissées sur le système.
Étape 2 – Math_Symbol.js / math_init.js (vol de données) : un ensemble compilé de 727 680 octets, fortement obfusqué, exécuté via le moteur d’exécution Bun. Il s’agit du moteur central de collecte d’identifiants. Les deux noms de fichiers (Math_Symbol.js et math_init.js) ont été observés en milieu naturel ; ils contiennent des fonctionnalités identiques et présentent le même hachage SHA-1.
Cibles de la collecte d’identifiants
Le voleur d’informations répertorie et exfiltre systématiquement :
Mécanismes de persistance
Le référentiel Keyv conservait des hooks distincts pour Claude Code (.claude/settings.json) et Visual Studio Code (.vscode/). Ces mécanismes de persistance au niveau de l’IDE peuvent exécuter la charge utile dès qu’un utilisateur fait confiance à l’espace de travail ou autorise la configuration du projet, offrant ainsi une voie d’exécution secondaire indépendante des scripts du cycle de vie de npm install.
Le logiciel malveillant installe également un observateur de révocation des identifiants — un piège qui déclenche un gestionnaire local fourni par l’attaquant lorsque les jetons sont renouvelés. Les intervenants doivent supprimer cet observateur avant de renouveler tout identifiant.
Commande et contrôle
Le logiciel malveillant récupère ses domaines C2 à partir d’un contrat intelligent Ethereum (StringListStore) à l’aide d’un appel eth_call, plutôt que de les intégrer dans la charge utile. Cette résolution C2 basée sur la blockchain permet à l’opérateur de mettre à jour l’infrastructure sans modifier le logiciel malveillant. L’historique sur la blockchain montre que le contrat avait initialement été configuré avec trois domaines avant d’être mis à jour pour ne renvoyer que npm-cache[.]com. Le propriétaire du contrat a été financé par une adresse précédemment signalée pour des activités frauduleuses.
Exfiltration
Les données volées sont chiffrées à l’aide d’un schéma hybride AES-256 et RSA-4096, puis exfiltrées via deux canaux :
Les premiers commits vers les dépôts d’exfiltration contiennent la menace suivante : « Si vous bloquez cette clé API, cela provoquera le plantage des serveurs de production en direct de tous les clients tiers. »
Indicateurs de compromission (IoC) connus
|
Catégorie |
Indicateur |
Description |
|
Domaine |
npm-cache[.]com |
Domaine principal de communication C2 et d'exfiltration de données ; hébergé via Cloudflare |
|
Domaine |
registry[.]npmjs[.]org |
Point de terminaison de validation des jetons utilisé de manière abusive pour la vérification en temps réel des identifiants avant l'exfiltration |
|
Domaine |
eth-mainnet[.]nodereal[.]io |
Point de terminaison RPC Ethereum utilisé pour la récupération de domaines C2 basés sur des contrats intelligents |
|
Domaine |
go[.]getblock[.]io |
Point de terminaison RPC Ethereum utilisé pour la récupération de domaines C2 via des contrats intelligents |
|
Domaine |
eth[.]llamarpc[.]com |
Point de terminaison RPC Ethereum utilisé pour la récupération de domaines C2 basés sur des contrats intelligents |
|
Domaine |
pypi-get[.]com |
Infrastructure supplémentaire contrôlée par les attaquants |
|
Domaine |
js-mirror[.]com |
Infrastructure supplémentaire contrôlée par les attaquants |
|
IPv4 |
104[.]21[.]35[.]216 |
Adresse IP Cloudflare associée à npm-cache[.]com |
|
IPv4 |
172[.]67[.]167[.]200 |
Adresse IP Cloudflare associée à eth[.]llamarpc[.]com |
|
IPv4 |
185[.]44[.]207[.]215 |
Adresse IP associée à go[.]getblock[.]io ETH RPC |
|
IPv4 |
35[.]175[.]164[.]77 |
Adresse IP AWS associée à eth-mainnet[.]nodereal[.]io |
|
Nom de fichier |
Math_Symbol.js |
Charge utile d'un voleur d'informations obfusquée (727 680 octets) ; déployée via les scripts de préinstallation du paquet npm |
|
Nom de fichier |
math_init.js |
Variante de la charge utile de vol d'informations présentant des fonctionnalités identiques |
|
Nom de fichier |
setup.mjs |
Dropper de phase 1 ; télécharge le runtime Bun et déclenche l'exécution de l'infostealer |
|
Hachage du fichier (SHA-1) |
35a672cf34b996b91f3e1c28cbf3a05a37e036e4 |
Math_Symbol.js / math_init.js : charge utile du programme de vol d'informations |
|
Hachage du fichier (SHA-1) |
686aa40d0fc22c8d569494543a0f891f359f2f99 |
setup.mjs situé dans le répertoire .claude (hook Claude Code) |
|
Hachage du fichier (SHA-1) |
f525d52ceb966516686b482d3dc0137028cc6a63 |
Fichier setup.mjs situé dans le répertoire .vscode (hook VS Code) |
|
User-Agent |
Bun/1.3.13 |
Chaîne User-Agent HTTP utilisée lors du téléchargement à l'exécution de Bun et des communications C2 |
|
Chemin d'accès au système de fichiers |
/tmp/bun-dl-*/ |
Répertoire temporaire utilisé pour le téléchargement du runtime Bun et la mise en attente |
|
Chemin d'accès au système de fichiers |
node_modules/keyv/Math_Symbol.js |
Emplacement de la charge utile de l’infostealer dans l’arborescence du paquet installé |
|
Chaîne |
Shai-Hulud : Et c'est reparti |
Description du dépôt GitHub utilisé pour les dépôts d’exfiltration |
|
Chaîne |
Si vous bloquez cette clé API, cela provoquera le plantage des serveurs de production en direct de tous les clients tiers |
Chaîne d'intimidation dans les commits initiaux d'exfiltration |
Détections et recherche de menaces
Les équipes de sécurité doivent mettre en œuvre les mesures de détection suivantes :
Mesures d'atténuation et de correction
Actions immédiates
Restauration du système
Analyse du cloud et du code source
Renforcement de la chaîne logistique
Si l’une des menaces décrites dans ce bulletin vous préoccupe ou si vous avez besoin d’aide pour déterminer les mesures à prendre afin de vous protéger contre les menaces les plus importantes auxquelles votre organisation est confrontée, veuillez contacter votre responsable de compte ou nous contacter pour savoir comment protéger votre organisation.