· Security musings

Catégories

Tags

🔍 Licence d'Utilisation 🔍

Sauf mention contraire, le contenu de ce blog est sous licence CC BY-NC-ND 4.0.

© 2025 à 2042 Sébastien Gioria. Tous droits réservés.

⏱️
Temps de lecture estimé
~6 minutes

Le 14 juillet 2026, pendant que la France regardait un défilé, des attaquants prenaient la main sur les pipelines de release de quatre dépôts GitHub du cœur d’AsyncAPI et publiaient cinq packages npm trojanisés sous le nom de campagne “miasma-train-p1”. Microsoft Threat Intelligence a tranché sur l’origine technique : un pull_request_target pwn request. Soit très exactement le montage que je décortiquais ici trois semaines plus tôt.


Il y a des articles dont j’aimerais autant qu’ils vieillissent mal. [Celui sur les pull_request_target ] (/2026/06/29/pwn-request-pull-request-target/) n’a pas eu cette chance. J’y écrivais que le pwn request “n’est pas une faille GitHub, c’est un motif générique qui existe partout où un trigger privilégié peut checkouter du code non vérifié”. Trois semaines après, AsyncAPI m’a fourni la démonstration, avec de vraies victimes en aval.

Note du PandaRedacteur : le sport favori du consultant sécu, c’est de dire “je vous l’avais bien dit”. Le mien, ce serait plutôt de ne jamais avoir l’occasion de le dire.

Je ne vais pas vous refaire la mécanique du pull_request_target, tout est dans l’article de juin. Ce qui m’intéresse aujourd’hui, c’est le détail de la branche de pré-production que tout le monde oublie.

Ce qui s’est passé chez AsyncAPI

Sur leurs branches principales, les mainteneurs d’AsyncAPI avaient fait le boulot. Protections strictes, revue par pairs obligatoire avant tout merge sur main => Nickel Chrome

Sauf que rien ne s’est joué sur main. Ça s’est joué sur next et schema ; deux branches de pré-production restées sans les mêmes garde-fous, probablement parce que personne ne s’est demandé si un pipeline de release pouvait s’y déclencher avec exactement les mêmes privilèges que sur la branche stable. Et bien sur la réponse => Bingo !

Note du PandaRedacteur : la branche “expérimentale”, celle qu’on garde “juste pour tester”, hérite systématiquement des permissions de prod sans hériter des contrôles de prod. On la trouve grlobalement a peut pres dans chaun des audits….

Pas de faille dans le code, pas de compte mainteneur volé : l’attaquant a joué sur un trou de process, ce qui est bien plus difficile à détecter dans un scanner. Il pousse du contenu vers ces branches non protégées, laisse le workflow pull_request_target faire le sale travail de checkout et d’exécution avec les privilèges du dépôt cible, et ressort par la voie royale du pipeline de release avec cinq packages npm trojanisés.

Vecteurs d’attaque : la fenètre, pas la porte

Ce cas ajoute une variante à l’exemple générique que j’avais construit en juin. Deux choses, en fait.

La porte blindée, la fenêtre ouverte

Verrouiller main ne vous protège de rien si next ou schema déclenchent les mêmes workflows privilégiés sans les mêmes contrôles. Et c’est précisément ce que cherche quelqu’un qui cartographie un projet open source avant de bouger : l’endroit où les protections s’arrêtent alors que les privilèges, eux, continuent tranquillement leur chemin.

Le pipeline de release, cheval de Troie

Une fois le pull_request_target exploité, plus besoin de s’attaquer à npm. L’attaquant a laissé le pipeline de release d’AsyncAPI publier pour lui. Les packages trojanisés sont donc sortis avec l’apparence de n’importe quelle version normale du projet, signés par l’infrastructure de confiance du mainteneur.

Ce que ça change dans la checklist de juin

En juin, je listais quatre réflexes : permissions par défaut en lecture seule, approbation humaine avant exécution privilégiée, runners éphémères, audit des définitions de pipeline. Je les maintiens tous les quatre. AsyncAPI m’oblige juste à écrire noir sur blanc ce que je considérais comme implicite : ces quatre réflexes s’appliquent à toute branche capable de déclencher un pipeline privilégié, pas seulement à la branche par défaut.

Note du PandaRedacteur : parfois il faut enfoncer la porte ouverte pour que les gens comprennent…

Autrement dit : tant que le pipeline de release regarde aussi next et schema, des règles limitées à main protègent le mauvais périmètre. Depuis le premier jour, et sans que personne s’en aperçoive.


À retenir 📌

  • Le pwn request théorique de juin s'est confirmé en juillet sur les pipelines de release d'AsyncAPI, avec cinq packages npm trojanisés à la clé.
  • Rien ne s'est joué sur la branche protégée `main` : tout est parti de `next` et `schema`, des branches de pré-production qui déclenchaient les mêmes privilèges sans les mêmes contrôles.
  • Le pipeline de release légitime a fait office de canal de diffusion pour un payload apparenté au RAT Miasma.
  • Étendez vos protections de branche à toute branche capable de déclencher un pipeline privilégié, pas uniquement à la branche par défaut.

Quelques références en lien