L'avis AD-2026-009 de l'Agence de cybersécurité de Singapour (CSA) a été publié le 6 août 2026 et était encore mis à jour le 7 septembre — un mois plus tard et toujours en mouvement, ce qui suffit à dire que l'incident n'est pas clos. L'ampleur : plus de 1 300 versions de paquets compromises sur le registre npm, représentant environ 2 milliards de téléchargements mensuels cumulés.
Les paquets empoisonnés sont des primitives de cache que presque personne n'installe directement
Les versions nommées comprennent keyv 6.0.0, cacheable 2.5.1, cacheable-request 13.0.20, flat-cache 6.1.24 et file-entry-cache 11.1.6. Notez leur point commun : presque personne ne les installe volontairement. Elles vivent au fond des arbres de dépendances d'ESLint, de clients HTTP et d'outils de build. « Je n'ai jamais installé ça » n'est donc pas une vérification valable — il faut réellement regarder l'arbre.
Ce qu'il vole : les clés SSH privées figurent sur la liste
Le logiciel malveillant s'appelle ChainDrop, une variante auto-propagée de la famille Shai-Hulud. Ce qu'il exfiltre : identifiants cloud, jetons GitHub, clés SSH, configurations Kubernetes et identifiants Terraform, envoyés vers le domaine npm-cache[.]com — un nom délibérément choisi pour ressembler à l'infrastructure de npm. Muni de ces éléments, il utilise les identifiants de publication volés pour empoisonner davantage de paquets : c'est exactement ainsi qu'il a atteint plus de 1 300 versions.
L'analyse de Microsoft Threat Intelligence du 4 août 2026 ajoute le détail d'exécution : plus de 400 paquets répartis sur plusieurs éditeurs sans lien entre eux, une charge utile JavaScript fortement obfusquée basée sur Bun, exécutée via le hook de cycle de vie preinstall de npm — avant même la fin de l'installation. Les fichiers de hook cités dans l'avis CSA sont setup.mjs, Math_Symbol.js et math_init.js.
Le point d'entrée initial n'avait rien d'exotique : un courriel d'hameçonnage déguisé en alerte de sécurité npm a permis de prendre le contrôle du compte d'un mainteneur.
Pourquoi les administrateurs de serveurs doivent s'en saisir
Le nœud du problème : un hook preinstall s'exécute sous votre identité. Tout ce que vous pouvez lire, il peut le lire. Et sur une machine qui sert la production tout en recevant à l'occasion un npm install, le même répertoire personnel contient typiquement :
~/.ssh/id_ed25519— probablement une clé qui ouvre d'autres serveurs sans mot de passe- les caches d'identifiants des CLI cloud, ainsi que mots de passe de base et clés d'API dans
.env ~/.docker/config.json,~/.kube/config,~/.terraform.d/
Autrement dit : sur un poste de développement, une attaque de la chaîne d'approvisionnement vole un accès au code ; sur un serveur, elle vole les clés de toute l'infrastructure.
Quatre choses à faire maintenant
- Inspectez l'arbre :
npm ls keyv cacheable cacheable-request flat-cache file-entry-cache. Vous pouvez aussi lire les versions épinglées directement dans le lockfile :grep -n "keyv\|flat-cache\|file-entry-cache" package-lock.json. - En cas de correspondance, considérez l'hôte comme compromis. La consigne de la CSA est directe : retirer les versions affectées, traiter les systèmes comme compromis, reconstruire les machines où des paquets malveillants ont été installés, faire tourner tous les identifiants exposés et vérifier les environnements cloud et de gestion de code. La rotation concerne les clés SSH, les jetons GitHub et les clés d'API cloud — pas seulement un changement de mot de passe.
- Vérifiez le trafic sortant historique vers
npm-cache[.]com. C'est la preuve directe que la charge utile s'est réellement exécutée. - Changez les habitudes : installez avec
--ignore-scriptsen CI et en production (npm ci --ignore-scripts), en traitant à part les rares paquets qui ont réellement besoin de scripts de build ; exécutez builds et services sous des utilisateurs distincts à privilèges réduits ; mettez une phrase secrète sur les clés SSH ; désactivez l'agent forwarding ; et gardez hors des machines de production les clés capables d'y pousser du code.
Séparer build et exécution est déjà un contrôle
Les pires conséquences frappent le montage « une machine fait tout » : hôte de build, hôte de production et coffre à clés en un seul endroit. Déplacez les builds sur une instance distincte qui ne détient aucun identifiant de production ni chemin sans mot de passe vers la production, et un paquet empoisonné ne vous coûte qu'une machine reconstructible à volonté. Déployer une application Node.js sur un VPS avec PM2 traite de la séparation des processus et des utilisateurs, et les stratégies de sauvegarde VPS expliquent ce qui doit être vrai pour que « reconstruire » soit une option réelle. Les instances SharkCloud sont facturées à l'heure et recréables à la demande : une machine de build dédiée coûte bien moins qu'une seule fuite d'identifiants.