4 points par GN⁺ 2025-12-15 | 3 commentaires | Partager sur WhatsApp
  • Le package npm malveillant Shai-Hulud 2.0 a compromis la machine d’un développeur et permis de s’emparer de l’accès à l’organisation GitHub de Trigger.dev
  • L’infection a commencé lorsque le développeur a exécuté pnpm install, ce qui a déclenché le script preinstall du package malveillant ; l’outil TruffleHog a ensuite été utilisé pour voler des identifiants
  • Pendant 17 heures, l’attaquant a cloné 669 dépôts, puis a tenté en 10 minutes de forcer des pushs sur 199 branches et de fermer 42 PR
  • Les packages et les systèmes de production n’ont pas été compromis ; l’attaque a été détectée en 4 minutes et l’accès au compte a été bloqué
  • Après l’incident, l’équipe a renforcé sa sécurité avec la désactivation des scripts npm, la mise à niveau vers pnpm 10, le déploiement npm via OIDC et la protection systématique des branches

Vue d’ensemble de l’attaque

  • Le 25 novembre 2025, pendant un débogage interne sur Slack, une anomalie a été repérée : plusieurs dépôts recevaient un commit « init » au nom de Linus Torvalds
  • L’enquête a montré que le ver de supply chain Shai-Hulud 2.0 avait compromis la machine d’un développeur et volé des identifiants GitHub
  • Ce ver aurait infecté plus de 500 packages npm et affecté plus de 25 000 dépôts
  • Les packages npm officiels de Trigger.dev (@trigger.dev/*, CLI) n’ont pas été infectés

Chronologie de l’attaque

  • 24 novembre, 04:11 UTC : début de la diffusion du package malveillant
  • 20:27 UTC : infection de la machine d’un développeur en Allemagne
  • 22:36 UTC : premier accès de l’attaquant et début du clonage massif de dépôts
  • 15:27~15:37 UTC (25 novembre) : phase d’attaque destructrice pendant 10 minutes
  • 15:32 UTC : détection de l’anomalie et blocage de l’accès en 4 minutes
  • 22:35 UTC : restauration complète de toutes les branches

Processus d’infection

  • Quand le développeur a exécuté pnpm install, le script preinstall du package malveillant s’est lancé, a téléchargé puis exécuté TruffleHog
  • TruffleHog a analysé et exfiltré les tokens GitHub, identifiants AWS, tokens npm, variables d’environnement, etc.
  • Le répertoire .trufflehog-cache et des fichiers associés ont été retrouvés sur la machine infectée
  • Le package à l’origine de l’infection ayant été supprimé, il n’a pas pu être retracé

Activité de l’attaquant

  • Après l’infection, une phase de reconnaissance a duré 17 heures
    • 669 dépôts ont été clonés via une infrastructure située aux États-Unis et en Inde
    • Les activités du développeur ont été surveillées afin de conserver l’accès via le token GitHub
    • Un dépôt nommé « Sha1-Hulud: The Second Coming » a été créé, probablement pour stocker des identifiants
    Publicité
  • Puis, une phase de destruction de 10 minutes a suivi
    • Tentatives de push forcé sur 199 branches dans 16 dépôts
    • Fermeture de 42 PR, certaines ayant été bloquées par la protection de branche
    • Tous les commits apparaissaient sous la forme « Linus Torvalds <email> / init »

Détection et réponse

  • L’anomalie a été détectée en temps réel via des alertes Slack
  • En 4 minutes, l’accès GitHub du compte compromis a été bloqué, puis tous les accès aux services AWS, Vercel, Cloudflare, etc. ont été révoqués
  • L’analyse des logs AWS CloudTrail a montré uniquement des appels API en lecture seule, sans accès aux données de production
  • AWS a aussi détecté séparément une activité suspecte liée à Shai-Hulud et envoyé une alerte

Impact et restauration

  • 669 dépôts clonés, 199 branches visées par des pushs forcés, 42 PR fermées
  • L’absence de reflog côté serveur sur GitHub a compliqué la restauration, mais l’équipe a pu tout rétablir en 7 heures grâce à l’Event API et aux reflogs locaux
  • Les packages npm et l’infrastructure de production n’ont pas été compromis

Exposition d’une clé GitHub App

  • Pendant l’enquête, une clé privée GitHub App a été retrouvée dans la corbeille du laptop du développeur
  • Cette clé disposait de droits read/write sur les dépôts clients et a été immédiatement renouvelée
  • La base de données (où sont stockés les ID d’installation) n’ayant pas été compromise, aucune preuve d’accès aux dépôts clients n’a été trouvée, sans qu’un risque puisse être totalement exclu
  • Des logs supplémentaires ont été demandés au support GitHub et un e-mail d’information a été envoyé aux clients

Analyse technique de Shai-Hulud

  • Lors de l’exécution de setup_bun.js, le runtime Bun est installé et bun_environment.js est lancé en arrière-plan
  • TruffleHog est utilisé pour collecter les identifiants présents dans le répertoire $HOME
  • Les données collectées (contents.json, cloud.json, truffleSecrets.json, etc.) sont téléversées vers des dépôts GitHub aléatoires avec un encodage base64 triple
  • Si un token npm est présent, le ver modifie et republie les packages du compte infecté afin de se propager
  • En l’absence d’identifiants, il tente de supprimer le répertoire personnel
  • Fichiers indicateurs de compromission : setup_bun.js, bun_environment.js, .trufflehog-cache/, etc.
Publicité

Mesures de renforcement de la sécurité

  • Désactivation complète des scripts npm (ignore-scripts=true)
  • Mise à niveau vers pnpm 10 : scripts désactivés par défaut, configuration de minimumReleaseAge (3 jours) pour retarder l’installation de nouveaux packages
  • Adoption de npm Trusted Publishers basé sur OIDC pour éliminer les tokens de longue durée
  • Protection de branche activée sur tous les dépôts
  • Déploiement de Granted sur AWS SSO, avec chiffrement des tokens de session
  • Dans GitHub Actions, approbation désormais requise avant d’exécuter les workflows des contributeurs externes

Enseignements pour les autres équipes

  • Le simple fait que l’installation npm puisse exécuter du code arbitraire constitue en soi une surface d’attaque
  • Il faut activer ignore-scripts=true et ne mettre en liste blanche que les packages réellement nécessaires
  • pnpm minimumReleaseAge permet de retarder l’installation des nouveaux packages
  • La protection de branche et le déploiement via OIDC sont des mesures de sécurité indispensables
  • Il ne faut pas stocker d’identifiants longue durée sur les machines locales ; les déploiements doivent passer uniquement par la CI
  • Le bruit des alertes Slack s’est révélé être la clé de la détection

Dimension humaine

  • Le développeur infecté n’est pas en faute : il a été compromis pour avoir simplement exécuté npm install
  • Pendant l’attaque, il a aussi été constaté que le compte concerné avait automatiquement ajouté en favori des centaines de dépôts aléatoires
  • L’incident révèle non pas une erreur individuelle, mais une vulnérabilité structurelle de l’écosystème

Indicateurs récapitulatifs

  • Délai entre l’infection initiale et la première attaque : environ 2 heures
  • Durée de maintien de l’accès par l’attaquant : 17 heures
  • Durée des actions destructrices : 10 minutes
  • 5 minutes jusqu’à la détection, 4 minutes jusqu’au blocage
  • 7 heures jusqu’à la restauration complète
  • Dépôts clonés : 669 / branches affectées : 199 / PR fermées : 42

Ressources de référence

  • Socket.dev : Shai-Hulud Strikes Again V2
  • Rapports d’analyse de PostHog, Wiz, Endor Labs et HelixGuard
  • Documentation npm Trusted Publishers, pnpm onlyBuiltDependencies, minimumReleaseAge, Granted

3 commentaires

 
click 2025-12-15

Avec pnpm, la structure semble exiger par défaut d’autoriser post-install individuellement, mais au final les développeurs finissent probablement eux aussi par l’autoriser inconsciemment.

 
lamanus 2025-12-16

Je comprends qu’ils ont renforcé la sécurité en passant à pnpm, puisque npm s’exécute par défaut, afin de le désactiver par défaut.

 
GN⁺ 2025-12-15
Commentaires sur Hacker News
  • Exécuter npm install n’est pas de la négligence
    Le vrai problème, c’est un écosystème qui autorise l’exécution de code arbitraire pendant l’installation des paquets
    Mais l’échec de sécurité fondamental, c’est d’utiliser un gestionnaire de paquets qui permet à un tiers d’injecter du code dans mon produit sans aucune vérification
    Au final, nous dépendons indéfiniment de la bonne volonté et des compétences des gestionnaires de paquets et de leurs mainteneurs
    Et l’OP semble aussi laisser entendre qu’il stockait des identifiants en clair sur le système de fichiers

    • Je pense que les deux sont des problèmes
      On peut concevoir, au niveau du langage, une structure qui limite le code à lire des entrées, consommer des ressources et ne produire que des sorties correctement typées
      Ce n’est pas une solution complète au problème de la supply chain, mais cela réduit fortement la surface d’exposition
    • Cette logique est trop circulaire
      C’est du genre : « ce n’est pas une erreur qu’une personne utilise cet outil, mais si tout le monde l’utilise alors l’écosystème devient problématique »
      Le fait que beaucoup d’outils de développement aient déjà des failles de sécurité a été démontré à maintes reprises
      Si on s’en soucie vraiment, il faut le montrer par des actes
    • C’est pareil pour les plugins d’IDE
      Avec VS Code, c’était pénible de devoir installer un plugin fait par on ne sait qui juste pour ajouter une petite fonctionnalité
    • Je me demande comment on pourrait concevoir un gestionnaire de paquets qui empêche l’exécution de code tiers
      J’ai l’impression que, de toute façon, on finit toujours par exécuter du code qu’on est obligé de considérer comme fiable
    • Certains outils ne prennent en charge que le fichier netrc pour l’authentification http
      Si on utilise git via http, ce vecteur d’exposition d’identifiants en clair existe presque toujours
  • Le mainteneur de pnpm avait proposé il y a un an de bloquer par défaut les scripts post-install
    Du point de vue de l’utilisateur, cela aurait été inconfortable, mais il pensait que tout le monde finirait par s’en féliciter à long terme
    PR associée : pnpm/pnpm#8897

    • Et pourtant, le même problème continue de se répéter
      C’est encore un cas où la praticité l’a emporté sur la sécurité
  • Ils ont dit que « la base de données n’avait pas été compromise », mais si l’attaquant a eu accès à AWS et aux secrets, alors pour moi il y a déjà eu compromission
    S’il y avait une possibilité d’accès, cela doit être considéré comme une compromission

    • S’il existe des logs d’accès aux ressources AWS et qu’aucune trace d’accès n’apparaît avant la révocation des droits, on peut considérer que les données sont restées sûres
  • Une fois le malware exécuté, il devient presque impossible de remonter à la source
    pnpm install se termine normalement, donc c’est difficile à détecter
    Avec un EDR comme Sentinel One ou CrowdStrike, il y aurait probablement eu plus de pistes pour l’enquête

    • S’il y avait eu un EDR, il est fort probable qu’il aurait détecté ou bloqué la chaîne d’attaque Trufflehog
  • Le passage disant « 669 repo ont été clonés au total » m’a marqué
    Je me demande s’il est normal qu’une entreprise de moins de 100 employés ait plus de 600 repo

    • C’est tout à fait normal. Les repo sont du bétail, pas des animaux de compagnie
    • Dans notre organisation, nous sommes 7 mais nous avons 365 repo sur GitHub
      Le nombre de repo dépend davantage de l’ancienneté et du cycle de vie des projets que de la taille de l’équipe
    • C’est ce qu’on obtient quand on a un architecte amateur de microservices
  • pnpm a déjà cessé d’exécuter automatiquement les scripts de cycle de vie comme preinstall, donc ils semblent avoir utilisé une ancienne version
    Voir la PR associée

    • L’article mentionne à la fin qu’ils ont mis à jour vers la dernière version majeure
    • Je pensais que c’était justement la raison principale d’utiliser pnpm, donc ça me laisse perplexe
    • Si, au final, ils ont mis à jour les dépendances avec un ancien gestionnaire de paquets, alors c’est de leur responsabilité
    • Il est aussi possible que le projet lui-même ait eu un script postinstall
      pnpm bloque les scripts des dépendances, mais exécute encore les scripts au niveau du projet
  • Merci d’avoir partagé un post-mortem transparent
    Ce genre de cas est important pour toute l’industrie
    Je me demande si le trafic d’attaque était identifiable par rapport au trafic de développement normal
    Nous essayons nous aussi de renforcer le filtrage egress dans l’environnement de dev, mais npm install casse souvent, donc c’est compliqué

    • Utiliser la liste d’autorisation IP des organisations GitHub pourrait aider à se défendre contre ce type d’attaque
  • Je réfléchis à la sécurité de git sur mon ordinateur portable personnel
    Pour l’instant, je fais les push avec une clé SSH stockée en local
    J’ai aussi des droits administrateur, donc c’est risqué. Je me demande comment rendre ça plus sûr

    • Je recommande d’utiliser 1Password pour gérer les clés SSH et la signature Git, puis de faire les push/pull via GitHub OAuth ou une connexion CLI
      Cela permet de séparer les clés de signature et les clés d’accès, et de gérer séparément le compte administrateur
      Documentation associée : 1Password SSH Agent, Git Commit Signing, GitHub OAuth, GitHub CLI Login
    • Moi, je stocke ma clé privée SSH dans le TPM et je l’utilise depuis l’agent SSH via PKCS11
      L’avantage, c’est que la clé ne peut pas être exfiltrée, mais si un malware tourne sur ma machine, cela reste dangereux
      Exemple Linux, exemple macOS
    • Si l’ordinateur portable est infecté, il n’y a pas vraiment de défense
      On peut compliquer un peu les choses avec un TPM ou une Yubikey, mais une protection totale est impossible
      Le plus sûr est d’effectuer les tâches d’administration sur une machine dédiée séparée
    • Il y a aussi la possibilité de mettre une clé GPG sur une Yubikey et d’utiliser gpg-agent pour l’authentification SSH
      On la déverrouille en saisissant un PIN au moment du push ou du commit
    • Si on bloque les push directs sur la branche principale et qu’on rend le MFA obligatoire, il devient plus difficile pour un attaquant d’accéder immédiatement à la branche de déploiement
  • Le commit au nom de Torvalds était une signature fréquemment observée après infection
    C’est aussi mentionné dans l’analyse officielle de Microsoft
    Ce ver était très bruyant, et certains attaquants ont exploité des identifiants exposés pour rendre publics des repo privés ou modifier des readme à des fins promotionnelles

  • Je me demande si une telle détection aurait été possible si l’attaquant s’était contenté d’exfiltrer discrètement des informations sans sabotage