Aikido

Keyv et ses amis ont été victimes d'une attaque active de type « Shai-Hulud » visant la chaîne d'approvisionnement

Écrit par
Ilyas Makari

Le 4 août 2026, des attaquants ont compromis le compte GitHub du mainteneur responsable de keyv, une bibliothèque de stockage clé-valeur enregistrant environ 127 millions de téléchargements npm hebdomadaires, et a profité de cet accès pour injecter un ver de vol d'identifiants dans toute la famille de paquets. Le même mainteneur possède cacheable (29 millions de téléchargements/mois), flat-cache (565 millions de téléchargements/mois), file-entry-cache (557 millions de téléchargements/mois) et plusieurs autres utilitaires de mise en cache très utilisés, qui ont tous été touchés par la même attaque.

La compromission a été menée en poussant des fichiers malveillants directement vers principal branche, puis en publiant immédiatement une nouvelle version, ce qui signifie que les versions empoisonnées ont été déployées sur npm avec une traçabilité valide signée par GitHub Actions.

Les paquets compromis incluent :

  • keyv 6.0.0 (604M/mois)
  • flat-cache 6.1.24 (580M/mois)
  • file-entry-cache 11.1.6 (571M/mois)
  • cacheable-request 13.0.20 (137M/mois)
  • cacheable 2.5.1 (30M/mois)
  • @cacheable/memory 2.2.1 (28M/mois)
  • cache-manager 7.2.10 (16M/mois)
  • @cacheable/node-cache 3.1.2 (6M/mois)
  • @cacheable/utils 2.5.1 (34M/mois)
  • @cacheable/net 2.1.1 (3,7 k/mois)
  • ecto 5.0.1 (4,5 k/mois)

Nous constatons également une propagation communautaire très active de ce ver de la chaîne d'approvisionnement vers d'autres mainteneurs et paquets, touchant notamment des organisations majeures :

  • @deliveroo/reevent 1.0.1
  • @or-sdk/invitations 1.4.9
  • @picsart/ai-sdk 3.32.2
  • @qlik/embed-runtime 1.6.4
  • picasso.js 2.11.6

Mise à jour — 5 août 2026, 13:15 CEST : Au moins 444 paquets (répartis sur 1 381 versions) ont été compromis par le ver, représentant un total cumulé de plus de 2 milliards de téléchargements mensuels au moment de la rédaction.

Ce qui s'est passé

Chaque paquet de la famille a reçu deux nouveaux fichiers, setup.mjs et Math_Symbol.js, ainsi qu'une "preinstall": "node setup.mjs" entrée ajoutée à chaque package.json. Quiconque a exécuté npm install contre une version vulnérable aurait eu setup.mjs s'exécuter automatiquement avant la fin de leur installation.

setup.mjs est un dropper lourdement obscurci. Son unique rôle est de télécharger silencieusement le runtime JavaScript Bun depuis github[.]com/oven-sh/bun/releases/download/bun-v1.3.13/ et de l'utiliser pour exécuter la véritable charge utile, Math_Symbol.js:

execFileSync(<bun binary>, ['<script_dir>/Math_Symbol.js'], {
  stdio: 'inherit',
  cwd: <script_dir>
})

Le Math_Symbol.js est un fichier JavaScript de 728 Ko fortement obfusqué contenant des logiciels malveillants de type stealers, conçus pour récolter des secrets dans l'environnement de la victime, chiffrer les données collectées et les exfiltrer vers un dépôt GitHub public dont la description indique : "Shai-Hulud : c'est reparti". La charge utile intègre également une fonctionnalité de propagation de type ver afin d'infecter les paquets d'autres mainteneurs ayant installé l'un des paquets compromis.

Ce qu'il dérobe

Le Math_Symbol.js Le fichier implémente un ensemble d'extracteurs d'identifiants, chacun ciblant un magasin de secrets différent sur la machine de la victime.

Tokens npm

Lit ~\/.npmrc et analyse le système de fichiers à la recherche d'autres .npmrc fichiers. Extrait les authToken valeurs ainsi que toutes les //registry.*:_authToken=... entrées. Valide chaque jeton en direct auprès de registry.npmjs[.]org/-/whoami avant de procéder à l'exfiltration.

Tokens GitHub

Trois formats de jetons sont visés : les PAT classiques (ghp_...) et les jetons OAuth (gho_...), les jetons serveur à serveur GitHub App (ghs_...) et les jetons JWT OIDC. Les sources incluent ~\/.config\/gh\/hosts.yml, les variables d'environnement et une analyse du système de fichiers.

Sur les exécuteurs GitHub Actions, la charge utile exécute également une commande shell qui lit directement la mémoire du processus de l'exécuteur pour vider l'ensemble du stockage de secrets. Elle lit ACTIONS_ID_TOKEN_REQUEST_TOKEN et ACTIONS_ID_TOKEN_REQUEST_URL pour dérober les jetons OIDC utilisés pour la publication sur npm.

Identifiants AWS

  • ~/.aws/credentials et ~\/.aws\/config, analysant tous les profils nommés
  • AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, et AWS_SESSION_TOKEN variables d'environnement
  • Le service de métadonnées d'instance EC2 sur 169.254.169.254, essayant d'abord IMDSv2 avec un repli sur IMDSv1
  • Le point de terminaison des métadonnées du conteneur ECS sur 169.254.170.2
  • AWS Secrets Manager, en appelant secretsmanager:ListSecrets dans plusieurs régions pour énumérer et exfiltrer tous les secrets qui y sont stockés

Les secrets Kubernetes

Lit le jeton de compte de service, le certificat CA et l'espace de noms depuis \/var\/run\/secrets\/kubernetes.io\/serviceaccount\/. Utilise le jeton de compte de service pour interroger directement l'API Kubernetes et récupérer tous les secrets de l'espace de noms. Cible également KUBECONFIG et ~/.kube/config.

Jetons HashiCorp Vault

Vérifie six sources par ordre de priorité : VAULT_TOKEN la variable d'environnement, ~/.vault-token, le chemin d'exécution des GitHub Actions /home/runner/.vault-token, plusieurs chemins de conteneurs connus, une connexion d'authentification Kubernetes utilisant le JWT du compte de service dérobé, ainsi que le point de terminaison d'authentification IAM AWS de Vault à l'aide de tous les identifiants AWS dérobés. Après avoir obtenu un jeton, il énumère tous les stockages KV via /v1/sys/mounts et lit chaque secret à partir des chemins KV v1 et v2.

Jetons Stripe et Slack

Analyse à la recherche de clés d'API Stripe (de test et de production, sk_ et pk_ préfixes) et de jetons Slack (xox[baprs]-...) dans tous les fichiers traités par le scanner de système de fichiers.

Analyse générique du système de fichiers

Un scanner compatible avec les plateformes (macOS vs Linux) exécute environ 200 motifs glob sur le système de fichiers, ciblant entre autres :

  • .env, .env.*, et .envrc fichiers
  • Fichiers de clés privées (*.pem, *.key, *.p12, *.pfx, *.jks)
  • Clés et configuration SSH (id_rsa, id_ed25519, .ssh/config)
  • Fichiers d'état Terraform et .tfvars
  • Fichiers d'identifiants de registre Docker (docker/config.json)
  • Bases de données KeePass (*.kdbx)
  • Configurations VPN (*.ovpn)
  • Fichiers de configuration IDE incluant .vscode/tasks.json et .claude/settings.json

Les fichiers de plus de 5 Mo sont ignorés. Jusqu'à 64 lectures simultanées sont utilisées. Un moteur d'expressions régulières générique est également appliqué à tous les fichiers analysés, signalant les clés privées PEM, les clés publiques SSH, les clés de stockage Azure, les chaînes de connexion aux bases de données avec des identifiants intégrés et les clé=valeur motifs correspondant aux noms de champs de secrets courants.

Exfiltration

Une fois les identifiants récoltés, la charge utile chiffre l'ensemble du paquet avant de l'envoyer. Seul l'attaquant, qui détient la clé privée RSA correspondante, peut déchiffrer les données ainsi téléversées. Cela signifie que les données volées reposent en toute visibilité sur une infrastructure publique tout en restant illisibles pour quiconque.

La principale destination d'exfiltration est un dépôt GitHub public dont la description contient la chaîne « Shai-Hulud: Here We Go Again ». Au moment de la rédaction, GitHub recense environ 1 300 dépôts publics correspondant à cette chaîne, chacun servant de point de dépôt pour le lot d'identifiants chiffrés d'une victime.

Si le téléversement vers GitHub échoue, la charge utile se replie sur https://npm-cache[.]com:443/router, un domaine enregistré le 22/05/2026 qui semble ne servir à aucune fin légitime. Ce domaine est récupéré dynamiquement à partir d'un smart contract Ethereum situé à 0xE1f2395ee43e45A1556EC6438a88c31B83493103, permettant à l'attaquant de faire pivoter son infrastructure à tout moment sans modifier la charge utile.

Ver auto-réplicatif

Au-delà du vol d'identifiants, la charge utile les utilise activement pour propager le malware à d'autres mainteneurs et dépôts. Elle possède deux vecteurs d'infection distincts.

Infection par archive tarball npm

À l'aide du jeton npm dérobé, la charge utile appelle https://registry.npmjs[.]org/-/npm/v1/tokens pour lister l'ensemble des paquets auxquels ce token a le droit de publier, puis récupère et décompresse l'archive tarball actuelle pour chacun d'eux. Avant de republier, il apporte les modifications suivantes :

  • Incrémente la version de correctif (patch) d'une unité (par exemple, 1.2.3 devient 1.2.4)
  • Ajoute "preinstall": "node setup.mjs" aux scripts du paquet
  • Injecte setup.mjs et math_init.js (fonctionnellement identique à Math_Symbol.js) dans le paquet

Il réempaquète et publie ensuite l'archive modifiée sur le registre.

C'est ainsi que le ver se propage au-delà du mainteneur initial. Après la compromission initiale du keyv mainteneur, nous avons observé plus de 400 paquets infectés par contamination au sein de la communauté. Ces infections de deuxième génération sont identifiables par l'utilisation de math_init.js plutôt que Math_Symbol.js, puisqu'elles ont été amorcées par le ver d'injection de tarball npm.

Infection de dépôt GitHub

Lorsque la charge utile (payload) trouve un ghs_ token, elle effectue des commits sur toutes les branches accessibles, jusqu'à 50 branches par dépôt, en traitant d'abord les branches les plus récemment actives et en sautant dependabot et copilot les branches. Elle ajoute des hooks malveillants à .claude/settings.json et .vscode/tasks.json de sorte que la charge utile s'exécute automatiquement la prochaine fois qu'un développeur ouvre le dépôt dans VS Code ou lance une session Claude Code à l'intérieur, sans qu'aucun npm install ne soit requis. Les commits sont signés par claude avec l'adresse e-mail claude@users.noreply.github[.]com et portent le message chore: update config, se fondant ainsi parmi de vrais commits.

Comment Aikido détecte cela

Si vous êtes un utilisateur Aikido, vérifiez votre flux central et filtrez les problèmes de logiciels malveillants. Cela apparaîtra comme un problème critique 100/100. Aikido effectue des rescans nocturnes, mais nous vous recommandons de déclencher un rescan manuel dès maintenant.

Si vous n'êtes pas encore un utilisateur Aikido, vous pouvez créer un compte et connecter vos dépôts. Notre couverture des logiciels malveillants est incluse dans le plan gratuit, aucune carte de crédit requise.

Pour une couverture plus large au sein de toute votre équipe, la Device Protection d'Aikido vous offre une visibilité et un contrôle sur les packages logiciels installés sur les appareils de votre équipe. Elle couvre les extensions de navigateur, les bibliothèques de code, les plugins d'IDE et les dépendances de build, le tout en un seul endroit. Arrêtez les malwares avant qu'ils ne soient installés.

Pour une protection future, envisagez Aikido Safe Chain (open source). Safe Chain s'intègre à votre flux de travail existant, en interceptant les commandes npm, npx, yarn, pnpm et pnpx et en vérifiant les paquets par rapport à Aikido Intel avant l'installation.

Indicateurs de compromission (IoC)

Fichiers

  • setup.mjs‍
    • SHA-256 54dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668
  • setup.mjs (version à propagation communautaire)
    • SHA-256 fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1eb
  • Math_Symbol.js et math_init.js‍
    • SHA-256 9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc

Réseau

  • https://npm-cache[.]com:443/router — point de terminaison d'exfiltration
  • eth-mainnet.nodereal[.]io requête contenant 0xE1f2395ee43e45A1556EC6438a88c31B83493103

Autre

  • Tout dépôt GitHub public dont la description contient "Shai-Hulud: Here We Go Again" — il s'agit des dépôts contrôlés par l'attaquant utilisés pour l'exfiltration d'identifiants.

‍

Partager :

https://www.aikido.dev/blog/keyv-and-friends-compromised-in-npm-supply-chain-attack

Analyser les malwares

Commencer gratuitement
4,7/5
Fatigué des faux positifs ?
Essayez Aikido, comme 100 000 autres.
Commencez maintenant
Obtenez une démonstration personnalisée

Approuvé par plus de 100 000 équipes

Réserver maintenant
Analysez votre application à la recherche d'IDORs et de chemins d'attaque réels

Approuvé par plus de 100 000 équipes

Démarrer l'analyse
Découvrez comment le pentest IA teste votre application

Approuvé par plus de 100 000 équipes

Démarrer les tests

Sécurisez vos systèmes dès aujourd'hui,
rapidement et gratuitement.

Sécurisez votre code, votre cloud et votre runtime au sein d'un système centralisé.
Connectez un dépôt pour découvrir ce que les agents de raisonnement trouvent dans votre base de code.

Aucune carte bancaire requise | Résultats de l'analyse en 32 secondes.
Utilisé par plus de 150 000 organisations