Mini Shai-Hulud frappe AntV : plus de 300 paquets npm malveillants publiés via le compte compromis d’un mainteneur
18 mai 2026
0 minutes de lectureUne attaque de la chaîne d’approvisionnement visant l’écosystème de visualisation de données @antv et des paquets npm associés se propage actuellement dans le registre npm. Attribuée à un groupe malveillant appelé TeamPCP et présentée comme une nouvelle vague de la campagne Mini Shai-Hulud, l’attaque a publié plus de 300 versions malveillantes réparties sur 323 paquets lors d’une vague automatisée de 22 minutes, le 19 mai 2026. Ces paquets représentent au total environ 16 millions de téléchargements par semaine.
Le vecteur d’attaque était un compte npm de mainteneur compromis. Le malware intégré aux paquets concernés dérobe les secrets des développeurs et les identifiants cloud, établit un accès C2 persistant et tente de se propager à d’autres paquets à l’aide de jetons npm volés.
En bref
Type d’attaque | Chaîne d’approvisionnement, compte de mainteneur compromis |
Acteur malveillant | TeamPCP (alias : DeadCatx3, PCPcat) |
Campagne | Mini Shai-Hulud (en cours depuis sept. 2025) |
Date de l’incident | 19 mai 2026, 01:39–02:06 UTC |
Paquets compromis | 637 versions malveillantes réparties sur 323 paquets |
Téléchargements hebdomadaires estimés | ~16 millions |
Comportement du malware | Vol d’identifiants, collecte de secrets cloud, persistance, propagation du ver |
Couverture Snyk | Avis dans la Snyk Vulnerability Database ; rapport Zero Day disponible dans l’application |
Mesures immédiates | Revenir à des versions antérieures au 19 mai, exécuter |
Paquets concernés
Le compte npm compromis atool gérait 547 paquets. La fenêtre de publication malveillante en a touché plus de 300, en deux vagues :
Première vague : 01:39–01:56 UTC (~317 versions)
Deuxième vague : 02:05–02:06 UTC (~314 versions)
Parmi les paquets concernés, voici ceux qui enregistrent le plus de téléchargements :
Paquet | Snyk Advisor | Téléchargements mensuels |
| 4,2 M | |
| 3,8 M | |
| 2,2 M | |
| 1,15 M | |
| 1,0 M+ |
Parmi les principaux paquets @antv compromis figurent @antv/g2, @antv/g6, @antv/x6, @antv/l7, @antv/s2, @antv/f2, @antv/g, @antv/g2plot, @antv/graphin et @antv/data-set, ainsi que des paquets sans portée, comme echarts-for-react, timeago.js, size-sensor et canvas-nest.js.
AntV est une suite de visualisation de données issue d’Alibaba, largement utilisée dans les tableaux de bord d’entreprise, les outils de reporting financier et les plateformes d’analyse de graphes. Son adoption étendue fait du portefeuille de paquets du compte de mainteneur une cible particulièrement intéressante.
Fonctionnement de l’attaque
Étape 1 : compromission du compte de mainteneur
L’attaque commence par la compromission du compte npm atool. Les circonstances de cette compromission font toujours l’objet d’une enquête. Une fois le compte sous son contrôle, l’attaquant pouvait publier les 547 paquets qu’il gérait.
Étape 2 : publication automatisée de paquets malveillants
L’attaquant a publié des versions malveillantes en deux vagues rapprochées, en poussant la plupart des paquets deux fois (un petit nombre de paquets utilisés lors des premiers tests a reçu trois versions). Chaque archive tar de paquet malveillant contient deux ajouts :
Un fichier
index.js:à la racine : une charge utile JavaScript Bun de 498 Ko fortement obfusquéeUne modification de
package.jsonajoutant :"preinstall": "bun run index.js"
Le hook de cycle de vie preinstall se déclenche automatiquement lorsqu’un développeur exécute npm install, avant toute autre opération d’installation.
Étape 3 : injection d’un commit orphelin pour la provenance Sigstore
L’une des techniques les plus subtiles de cette vague consiste à injecter une dépendance facultative pointant vers un commit orphelin dans le dépôt légitime antvis/G2 :
Il est important de noter que la dépendance provenant de GitHub reprend la même méthode d’attaque que celle utilisée lors de la précédente attaque de la chaîne d’approvisionnement TanStack Shai-Hulud.
Le commit a été créé par l’attaquant, mais falsifié pour sembler provenir de huiyu.zjt <huiyu.zjt@ant.com> (un véritable mainteneur). Aucun accès en écriture au dépôt ciblé n’était nécessaire. L’attaquant a forké antvis/G2, créé un commit orphelin contenant la charge utile, puis supprimé le fork. Le stockage d’objets de GitHub conserve les commits des forks supprimés jusqu’au passage du ramasse-miettes, ce qui laisse le commit malveillant accessible par son hash.
La récupération de ce commit permet d’exécuter la charge utile avec des identifiants issus de Git, tout en donnant l’impression de faire référence à un dépôt de confiance.
À l’aide de jetons OIDC GitHub Actions volés, le malware peut ensuite demander des certificats de signature à Fulcio (https://fulcio.sigstore.dev) et créer des attestations de provenance in-toto via Rekor (https://rekor.sigstore.dev), produisant ainsi des paquets accompagnés d’attestations SLSA Build Level 3 cryptographiquement valides.
Le point essentiel, ici, est que les signatures sont légitimes parce que le pipeline de build lui-même a été compromis. La provenance Sigstore indique quel pipeline a produit un artefact, mais pas si ce pipeline fonctionnait comme prévu. Il est donc erroné de croire que les preuves d’attestation, à elles seules, garantissent l’authenticité des paquets publiés.
Étape 4 : collecte des identifiants
Lorsque bun run index.js s’exécute sur la machine d’un développeur ou dans un exécuteur CI, la charge utile cible plus de 80 variables d’environnement et plus de 100 chemins de fichiers. Les types d’identifiants ciblés comprennent :
AWS : clés d’accès (
AKIA[0-9A-Z]{16}), jetons de session, EC2 IMDS (169.254.169.254), métadonnées ECS (169.254.170.2), Secrets ManagerGCP : fichiers JSON de comptes de service, identifiants par défaut des applications
Azure : identifiants de principaux de service
GitHub : PAT et jetons OIDC (
gh[op]_[A-Za-z0-9]{36,})npm : jetons de publication avec la portée
bypass_2faInfrastructure : jetons de service Kubernetes, jetons HashiCorp Vault
Bases de données : chaînes de connexion MongoDB, MySQL, PostgreSQL et Redis
Services : clés Stripe, jetons Slack, configurations d’authentification Docker
Clés SSH :
~/.ssh/id_*
Dans les environnements GitHub Actions, la charge utile tente de lire directement les secrets dans la mémoire du processus Runner.Worker via /proc/{pid}/mem, en contournant complètement le masquage des secrets.
Étape 5 : exfiltration des données
Tous les identifiants collectés sont sérialisés au format JSON, compressés avec gzip, chiffrés avec AES-256-GCM, puis la clé de chiffrement est protégée à l’aide de RSA-OAEP et d’une clé publique de l’attaquant codée en dur. Les défenseurs qui découvrent les données exfiltrées ne peuvent donc pas savoir ce qui a été volé.
L’exfiltration emprunte deux canaux :
C2 principal :
https://t[.]m-kosche[.]com:443/api/public/otel/v1/traces(dissimulé sous forme de données de traces OpenTelemetry)Point de dépôt GitHub secondaire : si un jeton GitHub est trouvé, la charge utile crée des dépôts sur le compte de la victime avec des noms inspirés de Dune (combinaisons de mots comme
sardaukar,fremen,atreidesavecsandworm,ornithopteroustillsuit, suivies d’un nombre de 0 à 999). Ces dépôts contiennent des fichiers README avec des phrases caractéristiques des vagues précédentes de la campagne Shai-Hulud, écrites à l’envers (par exemple : « niagA oG eW ereH :duluH-iahS »). Les données volées sont ajoutées sous le nomresults/results-<timestamp>-<counter>.json. Les requêtes HTTP utilisent"python-requests/2.31.0"comme User-Agent.
Étape 6 : persistance
La charge utile installe plusieurs mécanismes de persistance qui résistent à une simple commande npm uninstall :
Détournement d’agents de codage IA : crée un fichier
.claude/settings.jsoncontenant un hookSessionStartqui exécutenode .claude/setup.mjs. Le malware s’exécute à nouveau chaque fois qu’un développeur ouvre une nouvelle session Claude Code dans un répertoire concerné. Notons qu’il s’agit d’un schéma similaire à celui que nous avons observé lors de précédentes attaques de la chaîne d’approvisionnement, comme TanStack.Hooks d’IDE : modifie
.vscode/tasks.jsonavec"runOn": "folderOpen"pour se déclencher à l’ouverture du projet.Service au niveau du système d’exploitation : installe
~/.local/share/kitty/cat.py, un service d’arrière-plan qui interroge toutes les heures l’API de recherche de commits GitHub à la recherche de commandes contenant le mot-cléfiredalazer. Les commandes sont signées avec RSA-PSS à l’aide d’une clé publique codée en dur de 4096 bits, ce qui permet à l’attaquant d’envoyer du code Python arbitraire à exécuter sur les machines compromises, longtemps après l’infection initiale. Le service est enregistré comme service utilisateur systemd sous Linux (~/.config/systemd/user/kitty-monitor.service) et comme LaunchAgent sous macOS (~/Library/LaunchAgents/com.user.kitty-monitor.plist).
Surveillance des jetons : ~/.local/bin/gh-token-monitor.sh vérifie les jetons GitHub volés toutes les 60 secondes, permettant à l’attaquant de réagir rapidement lorsqu’un jeton est sur le point d’expirer.
Étape 7 : propagation du ver
La charge utile recherche les jetons npm disposant de la portée bypass_2fa et les utilise pour republier d’autres paquets que le compte compromis est autorisé à publier. Dans les environnements GitHub Actions, elle échange le jeton OIDC Actions contre des jetons npm de publication propres à chaque paquet via :
Elle injecte également un workflow GitHub Actions dans une branche nommée chore/add-codeql-static-analysis, avec un fichier de workflow intitulé "Run Copilot" (.github/workflows/codeql.yml). Le workflow exporte toJSON(secrets) dans un artefact nommé format-results.txt, puis supprime ses traces en effaçant l’exécution du workflow.
Analyse de l’impact
Le périmètre d’impact direct comprend tout environnement de développeur ou de CI ayant exécuté npm install avec une version de paquet concernée entre 01:39 et environ 02:18 UTC le 19 mai 2026.
Les environnements CI/CD présentent un risque accru. Dans ces contextes, la charge utile peut lire tous les secrets du processus de l’exécuteur, et pas seulement ceux explicitement transmis comme variables d’environnement. Tout secret auquel l’exécuteur GitHub Actions a accès — notamment les jetons OIDC, les secrets du dépôt et les secrets de l’organisation associés à ce dépôt — doit être considéré comme compromis si une version concernée a été installée.
Les machines des développeurs présentent également un risque important. Les mécanismes de persistance font que la suppression des paquets concernés ne suffit pas à éliminer la menace. Le hook .claude/settings.json, la tâche VS Code et le service système continuent tous de fonctionner tant qu’ils ne sont pas supprimés explicitement.
Le composant d’auto-propagation signifie que tout jeton npm récupéré sur une machine de développeur ou un exécuteur CI pourrait servir à contaminer d’autres paquets en dehors du portefeuille initial du compte atool, étendant ainsi le périmètre d’impact au-delà d’AntV et des paquets associés.
Détection
Vérifiez votre fichier de verrouillage. Si votre fichier package-lock.json ou yarn.lock référence un paquet géré par le compte atool, vérifiez si la version résolue a été publiée entre 01:39 et 02:18 UTC le 19 mai 2026.
Analysez vos projets avec Snyk. Snyk a publié des avis dans la Snyk Vulnerability Database concernant les versions de paquets affectées et a déployé une notification dans l’application ainsi qu’un rapport Zero Day pour aider ses clients à analyser leur exposition à l’échelle de leur organisation.
Pour analyser rapidement un paquet précis dans votre arborescence :
Recherchez les traces de persistance. Si vous avez installé des paquets concernés, vérifiez la présence des éléments suivants :
Indicateurs au niveau des paquets :
Présence du script
preinstallbun run index.jsdansnode_modules/<package>/package.jsonSHA256 de la charge utile :
a68dd1e6a6e35ec3771e1f94fe796f55dfe65a2b94560516ff4ac189390dfa1cDépendance facultative faisant référence à
github:antvis/G2#1916faa365f2788b6e193514872d51a242876569(ou aux commits7cb42f57561c / dc3d62a2181b)
Indicateurs réseau :
Requêtes sortantes vers
169.254.169.254ou169.254.170.2(points de terminaison des métadonnées cloud) depuis des environnements hors cloudRequêtes HTTP vers
t.m-kosche.com:443avec des chemins OpenTelemetryAppels à l’API GitHub avec l’User-Agent
python-requests/2.31.0ne provenant pas de véritables processus Python
Mesures correctives
Si vous ne savez pas si vous avez été touché, considérez qu’il s’agit d’une compromission avérée. Le chiffrement RSA des données exfiltrées vous empêche de récupérer ce qui a été dérobé.
Étape 1 : supprimez les mécanismes de persistance avant de révoquer les jetons.
Le démon gh-token-monitor.sh vérifie les jetons toutes les 60 secondes. Si un jeton GitHub expire ou est révoqué alors que le démon est en cours d’exécution, cela peut déclencher d’autres actions malveillantes. Arrêtez et supprimez d’abord les mécanismes de persistance :
Étape 2 : nettoyez npm et réinstallez avec des versions saines.
L’option --ignore-scripts empêche l’exécution des scripts du cycle de vie preinstall, postinstall ou prepare pendant l’installation. Elle devrait de toute façon être utilisée par défaut dans les environnements CI.
Étape 3 : renouvelez tous vos identifiants.
Partez du principe que tout ce qui est accessible depuis une machine ou un exécuteur CI ayant installé un package concerné est compromis :
Jetons de publication npm
Jetons d’accès personnels GitHub et secrets Actions
Clés d’accès AWS (et tous les rôles IAM accessibles depuis les exécuteurs concernés)
Clés de comptes de service GCP
Principaux de service Azure
Jetons de comptes de service Kubernetes
Jetons HashiCorp Vault
Clés SSH présentes sur les machines concernées
Chaînes de connexion aux bases de données
Toutes les clés API ou tous les jetons de service stockés dans des variables d’environnement ou des fichiers de configuration
Étape 4 : vérifiez sur GitHub la présence de workflows injectés et de dépôts de dépôt clandestin.
Étape 5 : évitez toute exposition future.
Activez l’authentification à deux facteurs npm avec la protection de publication pour tous les packages de votre organisation.
Ajoutez
npm install --ignore-scriptsà la configuration CI par défaut.Verrouillez les dépendances sur des versions précises à l’aide de fichiers de verrouillage avec vérification de l’intégrité.
Envisagez une politique de mise en attente dans le registre : signalez et retenez les packages publiés au cours des 7 derniers jours.
Utilisez Snyk pour surveiller en continu votre arbre de dépendances et repérer les packages malveillants dès qu’ils sont signalés.
Nous vous recommandons vivement de consulter le dépôt des bonnes pratiques de sécurité npm et de les appliquer afin d’adopter les contrôles et pratiques de sécurité nécessaires pour éviter de futurs incidents liés aux logiciels malveillants.
La campagne dans son ensemble : les vagues Shai-Hulud
L’attaque contre AntV est la dernière vague d’une campagne menée par TeamPCP depuis septembre 2025. Son évolution témoigne d’une escalade constante de son ampleur, de sa persistance, de sa sophistication et de l’exploitation d’infrastructures de confiance :
Vague | Date | Cible principale | Ampleur | Technique caractéristique |
Vague 1 (Shai-Hulud) | Sept. 2025 | npm (général) | ~4 packages | Premier ver npm à propagation autonome |
Vague 2 (SHA1-Hulud) | Nov. 2025 | Zapier, Posthog, Postman | Plus de 600 packages | Évasion de conteneurs ; logiciel destructeur d’effacement |
Vague 3 (Mini, SAP) | Avr. 2026 | SAP CAP-JS, MBT | 4 packages | Injection d’un hook Claude Code |
Vague 4 (TanStack) | 11 mai 2026 | @tanstack/* | 84 versions/42 packages | Première provenance SLSA valide obtenue par détournement d’OIDC |
Vague 5 (AntV) | 19 mai 2026 | @antv/* + 310 autres | 637 versions/323 packages | Compte de responsable de maintenance compromis ; C2 étendu |
Snyk a analysé en détail les vagues précédentes :
Chaque vague a réutilisé et enrichi la charge utile obfusquée basée sur l’environnement d’exécution Bun, en ajoutant de nouveaux mécanismes de persistance (le hook Claude Code SessionStart est apparu pour la première fois lors de la vague 3), de nouvelles infrastructures d’exfiltration et de nouvelles méthodes pour falsifier une provenance de confiance. Le problème de provenance SLSA mérite tout particulièrement votre attention : une attestation Sigstore valide confirme quel pipeline a produit un package, mais pas si ce pipeline a été compromis. Se fier à la provenance comme signal de confiance sans auditer également la configuration du pipeline sous-jacent laisse une faille que cette campagne a désormais exploitée lors de deux vagues consécutives.
Pour découvrir en vidéo comment utiliser Snyk pour remédier aux problèmes liés à l’ensemble de la campagne Shai-Hulud :

Attaque Shai-Hulud contre NPM : mesures correctives avec Snyk — Présentation de l’identification et de la correction des packages compromis à l’aide des outils Snyk.
Chronologie de l’attaque (19 mai 2026, UTC)
Heure | Événement |
01:39 | Publication de la première version malveillante depuis le compte |
01:56 | Fin de la première vague de publications (~317 versions) |
02:05 | Début de la deuxième vague |
02:06 | Fin de la deuxième vague (~314 versions supplémentaires) |
~02:18 | Détection ; les chercheurs en sécurité commencent à signaler l’incident |
En cours | L’enquête se poursuit ; d’autres packages pourraient être identifiés |
Couverture par Snyk
Snyk a publié des avis concernant les versions de packages touchées dans la Snyk Vulnerability Database. Les clients Snyk peuvent utiliser le rapport Zero Day intégré à l’application pour identifier les projets concernés au sein de leur organisation. Les entrées de la Snyk Vulnerability Database consacrées aux packages concernés présentent leur état de santé actuel.
Pour en savoir plus sur cette catégorie d’attaques, la leçon de Snyk Learn sur la compromission de packages légitimes explique comment la compromission d’un compte de responsable de maintenance s’inscrit dans le contexte plus large des menaces visant la chaîne logistique logicielle.
Sécurisez votre chaîne d’approvisionnement avec Snyk
87 % des personnes interrogées ont été touchées par des problèmes de sécurité de la chaîne d’approvisionnement. Protégez la vôtre avec Snyk.
