Rapport CTI technique du 6 août 2026
Résumé exécutif
Un ver auto-propagatif voleur d'identifiants, apparu dans la release keyv@6.0.0 le 4 août 2026, s'est étendu au-delà des namespaces Keyv et Cacheable pour toucher des centaines de paquets appartenant à plusieurs organisations distinctes. SafeDep a d'abord vérifié 353 versions empoisonnées réparties sur 79 noms de paquets, avant de réviser ce chiffre à 1 684 versions empoisonnées sur 420 noms de paquets rattachés à neuf organisations, en notant que le ver se déplaçait d'une organisation à l'autre toutes les deux à sept minutes et avait bouclé sa rafale de publication inter-organisations en environ trente minutes. Aikido a rapporté un total distinct et non directement comparable, ce qui illustre une difficulté réelle à cartographier l'ampleur exacte de la campagne en temps réel.
Le script preinstall de la release empoisonnée exécute un bundle compilé de 727 680 octets capable de collecter des identifiants GitHub, npm, cloud, Vault, Kubernetes, bases de données et clés privées, de lire la mémoire des runners GitHub Actions, d'installer un guetteur de révocation de jetons et d'embarquer les outils nécessaires pour republier automatiquement des paquets compromis sous une identité npm volée. Fait notable pour un public de pentesters et d'auditeurs de code : le dépôt Keyv contient toujours, au moment de la rédaction, des hooks .claude/settings.json et .vscode/tasks.json configurés pour exécuter la charge utile dès qu'une session Claude Code démarre ou qu'un projet s'ouvre dans VS Code, sous réserve que l'environnement de développement fasse confiance au workspace.
Chronologie
| Date | Événement |
|---|---|
| Non précisée | Un commit portant le badge de vérification GitHub et l'auteur github-actions[bot] plante les hooks Claude Code et VS Code dans le dépôt Keyv |
| 4 août 2026 | Publication de keyv@6.0.0, première release confirmée malveillante, avec script preinstall déclenchant la chaîne d'infection |
| 4 août 2026 | SafeDep vérifie un premier lot de 353 versions empoisonnées sur 79 noms de paquets |
| 4 août 2026, 17h40 IST | Des versions antérieures saines redeviennent latest pour au moins neuf paquets du lot initial (dont keyv@5.6.0, flat-cache@6.1.23, cache-manager@7.2.9), signe d'une reprise de contrôle partielle |
| 4 août 2026 (mise à jour) | SafeDep révise son décompte à 1 684 versions empoisonnées sur 420 noms de paquets rattachés à neuf organisations ; Aikido rapporte séparément au moins 868 paquets sur 1 381 versions, chiffre non cumulable avec celui de SafeDep |
| 4 août 2026 | 546 dépôts GitHub publics créés le même jour avec la description « Shai-Hulud: Here We Go Again » et un répertoire results/, potentiels artefacts d'exfiltration ou de mise en scène |
| 6 août 2026 | Publication du présent rapport CTI ; les répertoires .claude et .vscode piégés restent présents sur la branche main du dépôt Keyv |
Fiche vulnérabilité (format fiche CTI)
Cette campagne ne dispose pas d'identifiant CVE au moment de la rédaction. La fiche suivante adapte le format standard en fiche de campagne de compromission de chaîne d'approvisionnement.
Compromission npm keyv/cacheable | Sans CVE assignée | Écosystème npm, namespaces Keyv, Cacheable et paquets tiers republiés
Mécanisme : script preinstall déclenchant node setup.mjs, qui vérifie la présence du runtime Bun et télécharge la version 1.3.13 depuis les releases GitHub officielles du projet si nécessaire, avant de transférer l'exécution à un bundle compilé de 727 680 octets. Ce bundle, analysé par SafeDep, collecte du matériel d'identification GitHub, npm, cloud, Vault, Kubernetes, base de données et clé privée, lit la mémoire des runners GitHub Actions, installe un guetteur de révocation de jetons et embarque une mécanique de modification, versionnement et republication de paquets, documentée séparément par Socket. Conditions d'exploitation : exécution de npm install (ou équivalent) sur une version affectée dans un environnement où les scripts de cycle de vie de dépendances (preinstall, postinstall) sont autorisés à s'exécuter ; npm 12 bloque par défaut ces scripts non approuvés, mais les clients npm antérieurs et d'autres chaînes d'installation qui les permettent restent exposés. PoC disponible : sans objet, il s'agit d'une compromission de chaîne d'approvisionnement activement exploitée et documentée par observation directe (SafeDep, Socket, Aikido), pas d'une vulnérabilité logicielle avec preuve de concept distincte. Patch/mitigation : SafeDep indique que les versions empoisonnées de Keyv et Cacheable ont depuis été dépubliées, mais que le tag latest continuait, au moment de sa mise à jour, à pointer vers une version malveillante pour la plupart des autres noms de paquets affectés. Une simple mise à jour vers la dernière version disponible ne suffit donc pas à garantir l'assainissement : il faut comparer les lockfiles et versions résolues à la liste des paquets affectés plutôt que de se fier au tag latest.
Diagramme de la chaîne d'attaque

Timeline reconstituée à partir des décomptes successifs de SafeDep, Socket et Aikido publiés le 4 août 2026. Sources : The Hacker News, SafeDep, Socket, Aikido.
Analyse technique
Étape 1 : publication de la release piégée avec provenance valide
La release keyv@6.0.0 a ajouté node setup.mjs comme commande preinstall et inclus les fichiers setup.mjs et Math_Symbol.js dans le paquet publié, sans modifier le code de bibliothèque compilé lui-même, ce qui rend la charge utile difficile à repérer par une simple revue du code fonctionnel. Point notable pour l'analyse de chaîne d'approvisionnement : la release piégée est passée par le workflow GitHub Actions légitime du projet et porte donc une attestation de provenance OIDC et SLSA valide. Cette attestation certifie correctement le processus de build utilisé, mais ne peut en aucun cas établir que le code source entrant dans ce processus était lui-même sain, un rappel utile que provenance valide et contenu sain ne sont pas équivalents.
Étape 2 : exécution du dropper en deux temps
Au moment de l'installation, le script preinstall exécute setup.mjs, qui vérifie la présence du runtime Bun sur la machine et télécharge la version 1.3.13 depuis les releases GitHub officielles si celle-ci est absente, avant de passer la main à un bundle compilé de 727 680 octets. Ce choix d'un runtime légitime et signé (Bun) comme intermédiaire d'exécution réduit la probabilité de détection par des heuristiques basées sur l'exécution de binaires inconnus.
Étape 3 : collecte d'identifiants à large spectre
Une fois actif, le bundle collecte du matériel d'authentification GitHub, npm, cloud, HashiCorp Vault, Kubernetes, bases de données et clés privées, et lit la mémoire des processus runners GitHub Actions pour y extraire des secrets potentiellement présents en clair pendant l'exécution de pipelines CI/CD. Un guetteur de révocation de jetons est installé en parallèle : SafeDep précise que ce guetteur se déclenche précisément au moment de la révocation des identifiants compromis, ce qui signifie que rotation et révocation doivent être traitées dans un ordre spécifique côté défense (voir remédiation).
Étape 4 : republication automatique et propagation inter-organisations
Le bundle embarque une mécanique complète de modification, versionnement et republication de paquets, que Socket a documentée séparément dans son analyse du code décodé. En s'appuyant sur les droits de publication npm disponibles via les identifiants volés, le ver a republié des versions piégées à travers au moins neuf organisations distinctes, en se déplaçant de l'une à l'autre toutes les deux à sept minutes selon SafeDep, pour une rafale complète de publication inter-organisations bouclée en environ trente minutes. Cette vitesse de propagation dépasse très largement la capacité de réaction manuelle d'une équipe de sécurité applicative, quelle que soit sa maturité en matière de supply chain.
Étape 5 : persistance côté dépôt via hooks IDE
Indépendamment de la chaîne d'infection côté npm install, le dépôt Keyv conserve une seconde voie d'exécution : le fichier .claude/settings.json contient un hook SessionStart qui appelle .vscode/setup.mjs, tandis que .vscode/tasks.json définit une tâche « Environment Setup » avec runOn: folderOpen qui appelle .claude/setup.mjs. VS Code bloque par défaut l'exécution automatique de tâches dans un workspace non approuvé et invite l'utilisateur avant de les autoriser ; Claude Code applique de même un mécanisme de confiance de workspace aux paramètres de projet fournis par un dépôt. Ces protections réduisent mais n'éliminent pas le risque pour un développeur qui accorderait sa confiance au dépôt sans vérification préalable du contenu de ces fichiers de configuration.
Indicateurs de compromission
| Type | Valeur |
|---|---|
| Première release malveillante confirmée | keyv@6.0.0 |
| Fichiers ajoutés au paquet piégé | setup.mjs, Math_Symbol.js |
| Commande preinstall injectée | node setup.mjs |
| Taille du bundle compilé de second stage | 727 680 octets |
| Runtime tiers utilisé comme intermédiaire | Bun 1.3.13, téléchargé depuis les releases GitHub officielles |
| Hook Claude Code planté | .claude/settings.json, déclencheur SessionStart appelant .vscode/setup.mjs |
| Hook VS Code planté | .vscode/tasks.json, tâche « Environment Setup » avec runOn: folderOpen appelant .claude/setup.mjs |
| Commit de plantation des hooks | Badge GitHub vérifié, auteur déclaré github-actions[bot] |
| Paquets restaurés en latest (échantillon) | keyv@5.6.0, flat-cache@6.1.23, cache-manager@7.2.9 |
| Marqueur de dépôts d'exfiltration potentiels | 546 dépôts GitHub créés le 4 août 2026 avec la description « Shai-Hulud: Here We Go Again » et un répertoire results/ |
MITRE ATT&CK
Cartographie construite à partir des éléments confirmés par SafeDep, Socket, Aikido et The Hacker News, il ne s'agit pas d'une attribution officielle vendeur mais d'une lecture technique de la chaîne observée.
| Tactique | Technique | ID | Justification |
|---|---|---|---|
| Initial Access | Trusted Relationship / Supply Chain Compromise | T1195.002 | Compromission de paquets open source légitimes largement dépendus dans l'écosystème npm |
| Execution | Command and Scripting Interpreter | T1059 | Exécution du script preinstall déclenchant node setup.mjs lors de l'installation |
| Persistence | Event Triggered Execution | T1546 | Hooks SessionStart (Claude Code) et runOn: folderOpen (VS Code) déclenchant l'exécution à l'ouverture de session ou de projet |
| Credential Access | Credentials from Password Stores / Unsecured Credentials | T1552 | Collecte de matériel d'authentification GitHub, npm, cloud, Vault, Kubernetes et clés privées |
| Credential Access | Steal Application Access Token | T1528 | Lecture de la mémoire des runners GitHub Actions pour en extraire des secrets d'exécution |
| Lateral Movement | Software Deployment Tools | T1072 | Republication automatique de paquets piégés sous une identité npm volée pour propager le ver à d'autres organisations |
Remédiation : checklist opérationnelle
- Comparer les lockfiles et les versions réellement résolues (pas le tag latest) à la liste des paquets et versions affectés avant de considérer un environnement comme assaini.
- Traiter tout poste ou runner ayant exécuté une version affectée comme entièrement compromis en matière d'identifiants, conformément à la recommandation de Socket, et non comme un simple incident de paquet à mettre à jour.
- Retirer d'abord le guetteur de révocation de jetons du malware avant de procéder à la rotation des identifiants exposés : révoquer en premier déclenche le gestionnaire local injecté par l'attaquant.
- Auditer les fichiers .claude/settings.json et .vscode/tasks.json de tout dépôt tiers avant d'accorder la confiance au workspace, en particulier la présence de hooks SessionStart ou de tâches runOn: folderOpen pointant vers des scripts de configuration.
- Passer à npm 12 ou configurer explicitement le blocage des scripts de cycle de vie de dépendances non approuvés (preinstall, postinstall) pour les chaînes d'installation qui le permettent encore.
- Surveiller les créations massives de dépôts GitHub portant une description ou un répertoire caractéristique de cette campagne (« Shai-Hulud: Here We Go Again », répertoire results/) comme indicateur de compromission secondaire au sein de son propre organisation GitHub.
- Ne pas se fier à une attestation de provenance OIDC/SLSA valide comme preuve de code source sain : elle certifie le pipeline de build, pas le contenu qui y entre.
Sources
- Keyv-Linked npm Worm Poisons Hundreds of Packages, Plants Claude Code and VS Code Hooks (The Hacker News)
- Keyv npm Supply Chain Compromise Analysis (SafeDep)
- Popular npm packages in the Keyv and Cacheable namespaces compromised in active supply chain attack (Socket)
- Keyv and Friends Compromised in npm Supply Chain Attack (Aikido)