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.

 

Aperçu de la vulnérabilité

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 :

  • les identifiants cloud : clés d’accès AWS, valeurs du SSM Parameter Store (avec WithDecryption: true), secrets AWS Secrets Manager, identifiants Azure et GCP
  • Secrets CI/CD : secrets GitHub Actions, y compris l’extraction des valeurs « isSecret »:true de la mémoire des runners auto-hébergés, jetons de workflow GitHub
  • Jeton de développeur : jetons d’accès personnels GitHub (préfixes ghp_, gho_, ghs_), jetons de publication npm (préfixe npm_), chaque jeton étant validé en temps réel via registry.npmjs.org/-/whoami avant son exfiltration
  • Secrets d’infrastructure : secrets Kubernetes de tous les espaces de noms accessibles, jetons HashiCorp Vault et secrets KV, identifiants Terraform, clés SSH, chaînes de connexion aux bases de données
  • Configuration de l’IA et de l’IDE : fichiers de configuration de l’API Claude, identifiants des services liés à l’IA
  • Portefeuilles de cryptomonnaies : fichiers et clés de portefeuilles locaux
  • Identifiants de service : clés API Stripe, Slack, Twilio et autres clés API tierces
  • Environnement complet du processus : toutes les variables d’environnement du processus compromis

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 :

  • Des dépôts GitHub publics créés sous des identités compromises, portant la description « Shai-Hulud : Here We Go Again »
  • Le domaine npm-cache[.]com

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 :

  • Audit des dépendances : analysez tous les fichiers package-lock.json, yarn.lock, pnpm-lock.yaml et bun.lockb à la recherche des paquets et versions concernés. Ne vous fiez pas aux balises actuelles du registre : utilisez exclusivement les versions résolues issues des fichiers de verrouillage.
  • Indicateurs au niveau du système de fichiers : recherchez sur les postes de travail de développement, les exécuteurs CI/CD et les serveurs de compilation la présence des fichiers Math_Symbol.js, math_init.js et setup.mjs dans les arborescences node_modules et les répertoires temporaires correspondant à /tmp/bun-dl-*/.
  • Surveillance du réseau : déclenchez des alertes en cas de connexions sortantes et de requêtes DNS vers npm-cache[.]com, pypi-get[.]com, js-mirror[.]com et les points de terminaison RPC Ethereum répertoriés dans les IOC ci-dessus. Surveillez la présence de la chaîne d’agent utilisateur « Bun/1.3.13 ».
  • Audit GitHub : examinez les organisations à la recherche de dépôts publics inattendus portant la description « Shai-Hulud : Here We Go Again » ou de commits contenant la chaîne d’intimidation.
  • Surveillance des scripts de préinstallation : auditez les fichiers package.json de tous les projets à la recherche d’entrées inattendues de scripts de préinstallation faisant référence à setup.mjs.
  • Confiance de l’espace de travail IDE : vérifiez la présence de fichiers .claude/settings.json et .vscode/ non autorisés susceptibles de charger des charges utiles externes.

 

Mesures d'atténuation et de correction

Actions immédiates

  • Identifier et supprimer les versions concernées : auditer tous les environnements et supprimer toute installation des versions malveillantes du paquet. Effectuer une mise à niveau vers des versions saines et vérifiées.
  • Supprimez d’abord le surveillant de révocation des identifiants : ne procédez pas à la rotation des jetons avant d’avoir supprimé le logiciel malveillant. La charge utile installe un surveillant qui se déclenche en cas de révocation d’un jeton. Une rotation prématurée des identifiants peut entraîner l’exécution d’un gestionnaire fourni par l’attaquant. Éliminez le logiciel malveillant des systèmes affectés avant de procéder à la rotation des identifiants.
  • Partir du principe que tous les identifiants ont été compromis : si une version affectée a été installée, considérer tous les identifiants accessibles dans cet environnement comme volés. Cela inclut les identifiants cloud, les jetons npm, les PAT GitHub, les clés SSH, les secrets CI/CD, les identifiants de base de données et les clés API tierces.
  • Effectuez la rotation de tous les identifiants exposés : après avoir supprimé le logiciel malveillant, procédez à la rotation : tous les jetons de publication npm, les jetons d’accès personnels GitHub et les jetons OAuth, les clés d’accès AWS IAM, les identifiants des entités de service Azure et GCP, les jetons de compte de service Kubernetes, les jetons HashiCorp Vault, les mots de passe de bases de données, les clés SSH et les clés d’API tierces (Stripe, Slack, Twilio, etc.).
  • Révoquer et réémettre les jetons npm/GitHub : utilisez les consoles d’administration npm et GitHub pour révoquer de force tous les jetons potentiellement exposés. Générez de nouveaux jetons avec les périmètres d’accès minimaux requis.

Restauration du système

  • Reconstruisez les systèmes affectés : considérez tout poste de travail de développement, tout exécuteur CI/CD ou tout serveur de compilation sur lequel un paquet malveillant a été installé comme potentiellement compromis. Reconstruisez-les à partir d’une image ou d’un instantané dont la propreté est avérée.
  • Vider les caches locaux : videz le cache npm (npm cache clean --force), le cache Yarn, le magasin pnpm et le cache Bun afin d’éliminer les paquets malveillants mis en cache.
  • Supprimez et recréez les environnements virtuels : ne vous contentez pas de revenir à une version antérieure des paquets affectés. Supprimez les répertoires `node_modules` et recréez entièrement les environnements virtuels Python.

Analyse du cloud et du code source

  • Auditez les environnements cloud : examinez AWS CloudTrail, les journaux d’activité Azure et les journaux d’audit GCP à la recherche d’appels API non autorisés datant de la période d’installation du paquet. Vérifiez s’il y a eu création inattendue d’utilisateurs ou de rôles IAM, accès au SSM Parameter Store avec décryptage, et accès à Secrets Manager.
  • Examinez les journaux d’audit GitHub : examinez les journaux d’audit de l’organisation pour détecter toute création inattendue de dépôts, génération de jetons et modification de workflows.
  • Recherchez les dépôts d’exfiltration : recherchez les dépôts publics créés sous les identités de votre organisation et comportant la description « Shai-Hulud : Here We Go Again ».

Renforcement de la chaîne logistique

  • Fixer les dépendances : utilisez le verrouillage de version exact dans tous les fichiers package.json et validez les fichiers de verrouillage dans le système de contrôle de version.
  • Passez à npm 12 : npm 12 bloque par défaut les scripts de cycle de vie des dépendances non approuvés, empêchant ainsi l’exécution automatique des scripts de préinstallation. Les versions antérieures de npm restent vulnérables.
  • Appliquez les normes SLSA et OIDC : exigez des attestations de provenance SLSA et vérifiez-les au moment de la compilation. Notez toutefois que cette campagne a démontré que la provenance seule est insuffisante lorsque l’attaquant contrôle le pipeline de compilation — la provenance doit être combinée à une vérification d’identité.
  • Activer la liste blanche des dépendances : limitez les sources et versions de paquets autorisées à l’aide d’outils tels que Socket, Semgrep Supply Chain ou les politiques de votre registre d’artefacts.
  • Mettez en place une vérification de l’intégrité des paquets : utilisez les signatures d’audit npm et vérifiez les hachages d’intégrité du registre lorsque cela est pris en charge.
  • Activer l’authentification multifactorielle (MFA) sur tous les comptes de mainteneurs : exiger une MFA matérielle pour tous les comptes npm et GitHub disposant de droits de publication.
  • Bloquez les domaines malveillants : ajoutez les indicateurs de compromission (IOC) répertoriés ci-dessus à vos listes de blocage du périmètre réseau et à vos solutions de filtrage DNS.

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.