Le retour de Shai-Hulud : plus de 300 paquets NPM infectés
(helixguard.ai)- Sur le registre NPM, plus de 1 000 composants ont été infectés en quelques heures selon la même méthode, et de nouvelles versions contenant du code malveillant ont été publiées
- Les paquets malveillants se faisaient passer pour un script d’installation du runtime Bun, en ajoutant
setup_bun.jsetbun_environment.jsobfusqué ; à l’exécution, ils utilisaient TruffleHog pour voler des identifiants locaux - Les informations sensibles collectées, dont des tokens AWS/GCP/Azure, GitHub et NPM, étaient exfiltrées via un runner GitHub Action nommé
SHA1HULUD - Le script malveillant exécutait automatiquement
npm publishafin d’assurer une auto-réplication de type ver, ce qui a abouti à l’infection de plus de 27 000 dépôts GitHub - Le cas est considéré comme un nouvel exemple mettant en lumière la menace sur la sécurité de la supply chain dans tout l’écosystème open source
Vue d’ensemble de l’attaque
- Le 24 novembre 2025, HelixGuard a détecté sur le registre NPM plus de 1 000 paquets infectés en quelques heures selon le même mode opératoire
- Les nouvelles versions se présentaient comme ajoutant le runtime Bun et incluaient le script
preinstall: node setup_bun.js - Le fichier
bun_environment.js, distribué avec elles, contenait un code malveillant obfusqué qui téléchargeait et exécutait TruffleHog
- Les nouvelles versions se présentaient comme ajoutant le runtime Bun et incluaient le script
- TruffleHog scannait l’environnement local pour voler des tokens NPM, identifiants AWS/GCP/Azure et variables d’environnement
- Les informations dérobées étaient exfiltrées en créant un runner GitHub Action
SHA1HULUD, puis via un dépôt GitHub portant la descriptionSha1-Hulud: The Second Coming. - HelixGuard estime que cette attaque pourrait être l’œuvre du même acteur que dans l’incident « Shai-Hulud » survenu en septembre 2025
Analyse du fonctionnement du code malveillant
- L’analyse du paquet
@asyncapi/specs, pris comme exemple, montre que la version publiée sur NPM était infectée, alors que le dépôt source sur GitHub restait sain - L’attaquant a modifié
package.jsonpour ajoutersetup_bun.js, puis a configuré ce script pour appelerbun_environment.js bun_environment.jsest un fichier JavaScript fortement obfusqué de plus de 10 Mo, dont les fonctions principales sont les suivantes- collecte d’identifiants cloud et de tokens à partir des variables d’environnement
- scan de secrets avec TruffleHog
- exfiltration de données via GitHub Actions
- Le code modifiait aussi
package.jsonpour y injecter l’infection, puis exécutait automatiquementnpm publishafin d’assurer une propagation de type ver
Infection de GitHub et exfiltration de données
- Le script malveillant créait le fichier
.github/workflows/formatter_123456789.ymlet enregistrait le runnerSHA1HULUD - Ce workflow empaquetait les secrets du dépôt dans un fichier
actionsSecrets.json, encodé en Base64 deux fois - Il créait ensuite un dépôt GitHub au nom aléatoire avec la description
Sha1-Hulud: The Second Coming.pour y téléverser les données - HelixGuard a confirmé que plus de 27 000 dépôts GitHub avaient été infectés
- Parmi les secrets dérobés figuraient des identifiants de nombreux services, dont
AWS_ACCESS_KEY_ID,SLACK_WEBHOOK_URL,CODECOV_TOKENetWEBFLOW_TOKEN
Liste des paquets infectés
- HelixGuard a signalé l’infection de centaines de paquets NPM
- Parmi eux, des paquets d’organisations majeures comme
@asyncapi,@ensdomains,@posthog,@zapier,@postmanet@voiceflow - Plusieurs versions de chaque paquet ont été touchées, par exemple
@asyncapi/specs@6.8.2et@postman/csv-parse@4.0.5
- Parmi eux, des paquets d’organisations majeures comme
- La plupart de ces paquets usurpaient l’apparence de projets open source légitimes, avec du code malveillant injecté dans le processus de déploiement automatisé
Enjeux de sécurité
- Cette attaque illustre comment des failles de sécurité de la supply chain peuvent être exploitées pour contaminer à grande échelle l’écosystème open source
- Elle met en évidence la nécessité de renforcer la sécurité de l’ensemble de l’infrastructure de développement, notamment autour de NPM, GitHub et des identifiants cloud
- HelixGuard recommande d’interrompre immédiatement l’installation des paquets infectés et de révoquer sans délai les tokens et identifiants concernés
5 commentaires
L’écosystème JS est vraiment un bordel sans nom, comme le dit le thread.
https://github.com/search/…
J’ai créé un script de scanner en temps réel.
Dans le chemin du dépôt suspect,
exécutez
npx sha1-hulud-scanner.Code source : https://github.com/developerjhp/sha1-hulud-scanner
Avis Hacker News
Petit conseil : mieux vaut utiliser PNPM plutôt que NPM
PNPM 10.x bloque plusieurs vecteurs d’attaque
1️⃣ Par défaut, il n’exécute pas les scripts post-install et exige une approbation manuelle
2️⃣ Il peut être configuré pour n’installer un paquet qu’après un certain délai suivant la publication d’une nouvelle version (par exemple 4 jours)
NPM est trop instable pour un environnement CLI de production
Il vaut mieux limiter les clés d’éditeur au strict minimum, les lier à des paquets précis et restreindre les IP à celles des runners CI/CD
Ne gardez pas de clé de publication en local ; si besoin, envisagez OIDC Trusted Publisher ou un accès par jeton
Rien que pour les lockfiles, ils s’y sont repris au moins cinq fois, et ce n’est toujours pas parfait
À voir la structure et l’historique des commits, on sent que l’équipe fait de gros efforts pour améliorer les choses, mais avec l’impression d’être partie d’un trou beaucoup trop profond
Il ne détecte toujours pas les EOF prématurés pendant les transferts de fichiers et laisse des fichiers incomplets dans le cache, ce qui fait perdre un temps fou sur les connexions lentes à cause des échecs de mise à jour
C’est plus complexe au départ, mais cela permet de gérer les secrets sous forme de bail (lease)
Un bail peut être créé pour chaque build CI puis révoqué automatiquement à la fin, avec prise en charge du TTL et de la rotation automatique
Cela permet de masquer les identifiants longue durée et de n’émettre que des jetons à courte durée de vie au moment du build
Grâce à ce type d’attaque, de vraies discussions sur la sécurité s’ouvrent enfin dans les entreprises, et c’est positif
npm ciComme seules les versions indiquées dans
package-lock.jsonsont installées, cela réduit le risque d’attaque lié aux mises à jour automatiquesL’important est de ne faire que des mises à jour intentionnelles
pip install --only-binary=:all:Cela bloque complètement les distributions source et n’installe que des wheel
En contrepartie, cela peut imposer des contraintes de version
Dans
uv, l’option--exclude-newerpermet d’imiter la fonctionnalité de « durée minimale avant installation » de PNPMJe fige toutes mes dépendances et j’examine manuellement les alertes dependabot
Je me demande encore si c’est excessif ou simplement une bonne habitude
Il y a justement aujourd’hui un article très pertinent : “We should all be using dependency cooldowns”
Les mises à jour automatiques de dépendances peuvent être plus dangereuses qu’une vulnérabilité d’un jour
Il est bien plus difficile de faire marche arrière sur un paquet infecté déjà propagé dans des milliers de lockfiles
Si tout fonctionne bien, il n’y a pas de raison d’y toucher
uvpour Python, on peut obtenir un effet similaire avec la commandeuv lock --exclude-newer $(date --iso -d "24 hours ago")La discussion correspondante est dans l’issue #14992
La commande
npx npm-check-updates -c 7permet de définir un cooldown de 7 joursVoir la documentation npm-check-updates
Un cooldown peut allonger le temps de propagation d’une vulnérabilité 0-day
Si tout le monde applique le même cooldown, cela ne fait que retarder la découverte
Je suis le cofondateur de PostHog
Nous avons été touchés par cette attaque
Les versions infectées sont posthog-node 4.18.1, 5.13.3, 5.11.3 / posthog-js 1.297.3 / posthog-react-native 4.11.1 / posthog-docusaurus 2.0.6
Nous avons remplacé toutes les clés et tous les mots de passe, et publié de nouvelles versions
Nous analysons actuellement la cause et publierons des mises à jour sur status.posthog.com
Si un site web a déployé la version compromise, j’aimerais savoir si ses visiteurs ont subi un préjudice
Question sérieuse : est-ce vraiment raisonnable de démarrer un nouveau projet avec Node
Je construis un frontend SaaS avec Astro, et chaque mise à jour de dépendance m’inquiète
L’absence de sécurité dans l’écosystème npm me paraît beaucoup trop grave
Même des écosystèmes comme Rust, qui dépendent d’innombrables sous-paquets, finiront par connaître la même chose
Des langages comme C, C++, ou Odin, sans gestionnaire de paquets central, font peut-être au contraire un choix plus judicieux du point de vue sécurité
Ces derniers temps, je fais davantage confiance à JSR de Deno
Les paquets basés sur JSR sont aussi publiés sur npm, et il existe également des paquets spécifiques à Deno
Par exemple, Lume m’a fait une bonne impression comme SSG lent mais stable
npm est simplement le plus grand registre, donc la cible la plus rentable pour les attaquants
Cela pourrait tout aussi bien arriver sur RubyGems ou Cargo
C’est juste l’écosystème le plus utilisé, donc celui qui concentre les attaques
Il suffit de gérer ses dépendances avec prudence et d’éviter de mettre à jour tous les jours
L’avantage, c’est qu’il n’y a pas besoin de plus de 100 dépendances juste pour rendre une page
Voir le lien du projet
En ce moment, je fais tout mon développement uniquement dans des conteneurs Podman
Je n’exécute du code non lu que dans un environnement isolé
Ce n’est pas parfait, mais je considère que c’est une habitude de sécurité minimale
En pratique, la sécurité est souvent un domaine délégué aux spécialistes, ce qui rend le changement difficile
Il y a 12 ans, NPM est déjà tombé complètement hors service une fois
À l’époque, ce n’était qu’un projet open source, mais aujourd’hui il appartient à Microsoft
Quand on est l’une des plus grandes entreprises du monde, on devrait pouvoir régler ce genre de problème, non ?
Pourtant, pas grand-chose n’a vraiment changé
Tout ce qui ne rapporte pas directement via les licences entreprise est laissé de côté
C’est pour ça que Windows 11 ressemble à un produit de pur marketing
Nous sommes actuellement en train de surveiller l’activité de l’attaque et de mettre à jour la liste des paquets infectés sur le blog Wiz
Nous faisons l’ingénierie inverse du payload malveillant et partagerons nos conclusions d’ici quelques heures
Le chat « Talk to a human » de PostHog m’a agacé, car il répondait en fait avec un robot
Le lien d’assistance d’urgence n’était pas indiqué correctement
Donc je repose la question — quelles versions faut-il éviter ?
Les versions infectées sont posthog-node 4.18.1, 5.13.3, 5.11.3 / posthog-js 1.297.3 / posthog-react-native 4.11.1 / posthog-docusaurus 2.0.6
Une mise à jour vers la dernière version est sûre
Je me demande pourquoi ce genre de chaos autour des paquets arrive toujours dans l’écosystème Node
Je ne comprends pas pourquoi cette communauté considère comme une bonne pratique d’ingénierie les hooks d’installation complexes et les mises à jour automatiques
Je comprends mieux pourquoi le créateur de Node a fini par partir
Un écosystème immense, centré sur les développeurs débutants, peu sensibilisé à la sécurité, et où même la moindre fonctionnalité dépend d’une bibliothèque
Comme dans Debian, il faudrait des responsables de confiance qui valident les paquets, mais la communauté JS rejette cela comme du gatekeeping
C’est pour ça que ce genre de crise se répète
Avec cette attitude, rien ne changera
C’est un peu hors sujet, mais je me demande qui est HelixGuard
Leur site web est mauvais et on trouve très peu d’informations
Ils disent avoir des plateformes d’échange crypto comme clients, ce qui paraît suspect
Compte X de HelixGuard
2️⃣ Il est possible de configurer l’installation pour qu’elle n’ait lieu qu’après un certain délai suivant le déploiement d’une nouvelle release (par exemple, 4 jours).
C’est une fonctionnalité vraiment excellente. Même Google publie parfois sur NPM des versions buguées qui ne fonctionnent pas, donc il m’arrive de me demander si le bug vient de chez moi et de paniquer un peu.