Le 18 mai 2026, 53 tags de l'action GitHub actions-cool/issues-helper
ont été réécrits en moins de 3 minutes 16 secondes pour pointer vers un
commit imposteur qui exfiltre les secrets CI/CD depuis la mémoire du
process Runner.Worker. Une seconde action de la même organisation,
actions-cool/maintain-one-comment, a subi le même traitement dans la même
fenêtre (15 tags en 39 secondes). Seuls les workflows épinglés par SHA de
commit légitime complet sont épargnés. Cet article décrit le mécanisme,
les IOCs publiés par StepSecurity, et l'action immédiate à mener si vous
utilisez l'une de ces actions.
Ce que vous allez apprendre
- Comprendre ce qu'est un commit imposteur dans une attaque par tag poisoning
- Identifier si vos workflows utilisent l'une des actions compromises
- Détecter les indicateurs de compromission côté runner
- Vous protéger par épinglage SHA et bloquer la sortie réseau du payload
- Renforcer votre posture après l'incident
Dans quel contexte ?
Cette attaque concerne tout dépôt qui consomme actions-cool/issues-helper
ou actions-cool/maintain-one-comment via un tag — typiquement
@v3, @v3.7.6, @v2. C'est le pattern par défaut quand on copie un
exemple de la Marketplace GitHub Actions : facile à écrire, fragile en
réalité. La règle de défense — épingler chaque action par le SHA complet
du commit — n'est plus une recommandation d'expert depuis le précédent
de tj-actions/changed-files en mars 2025. Mais elle reste encore
massivement ignorée, et chaque nouvelle compromission rappelle pourquoi.
Ce qui s'est passé
L'attaquant a obtenu la capacité de déplacer les tags dans le dépôt
GitHub actions-cool/issues-helper. Il a généré un commit imposteur
par tag — chacun avec un message de commit factice du style
"Build action for vX.Y.Z" qui imite la convention du mainteneur — et
re-pointé l'ensemble des 53 tags sur ces nouveaux commits, qui ne sont
rattachés à aucune branche du dépôt (commits orphelins).
Le tell est dans le timing : les 53 commits imposteurs ont tous été créés
entre 19:10:24 et 19:13:40 UTC le 2026-05-18. La même opération a été
menée 17 minutes plus tard sur maintain-one-comment, avec 15 commits
créés en 39 secondes. Un humain ne tape pas 53 commits artisanaux en 3
minutes — c'est de l'automatisation.
Côté payload, quand un workflow exécute l'action compromise sur un runner :
- Téléchargement du runtime JavaScript
bundans/home/runner/.bun/bin/bun. - Lecture de
/proc/<Runner.Worker PID>/memdepuis un process Python enfant. C'est ce process Runner.Worker qui détient les secrets déchiffrés du workflow. - Filtrage de la mémoire à la recherche de
"isSecret":true, puis extraction des tokens d'authentification (gh auth token, secrets de pipeline). - Exfiltration HTTPS vers
t.m-kosche.comsur le port 443.
Sources : l'analyse complète et les IOCs sont publiés par StepSecurity. Les mainteneurs ont été notifiés via l'issue #11 du dépôt.
Êtes-vous concerné ?
Lancez cette commande à la racine de chaque dépôt :
grep -rE "actions-cool/(issues-helper|maintain-one-comment)" \ .github/workflows/ 2>/dev/nullTrois cas de figure :
- Aucun résultat : vous n'utilisez pas ces actions. Lisez la suite pour les bons réflexes en prévention.
- Référence par tag (
@v3,@v3.7.6,@v2, etc.) : votre workflow est compromis dès le prochain run. Action immédiate ci-dessous. - Référence par SHA : vérifiez que le SHA ne fait pas partie des commits imposteurs. Tous les SHA dans la liste publiée par StepSecurity sont à proscrire. Si votre SHA n'y figure pas, il est probablement légitime — confirmez en vérifiant qu'il appartient à la branche par défaut du dépôt.
Action immédiate
Une fois la rotation faite, deux options pour la suite :
-
Supprimer l'usage de l'action si elle n'est pas critique. C'est l'option la plus sûre tant que les mainteneurs n'ont pas repris le contrôle du dépôt et publié une déclaration officielle.
-
Épingler sur le dernier SHA légitime — celui de la branche
masterà la veille de l'incident. Concrètement :# AVANT — vulnérable- uses: actions-cool/issues-helper@v3# APRÈS — SHA d'un commit légitime de la branche master- uses: actions-cool/issues-helper@<SHA-de-master-pré-18-mai-2026> # v3Pour récupérer un SHA légitime, ouvrez l'historique de la branche
masterdu dépôt sur GitHub à une date antérieure au 18 mai. Ne prenez pas un SHA depuis un tag — tous ont été détournés.
Si vous utilisez l'outil StepSecurity Harden-Runner avec egress block
mode, l'exfiltration vers t.m-kosche.com est déjà bloquée. Cela
n'empêche pas la lecture de mémoire mais bloque la fuite des secrets —
défense en profondeur.
Auditer son parc en une commande avec Plumber
Vérifier à la main que chaque uses: de chaque workflow est épinglé par
SHA ne tient pas la route au-delà d'une poignée de dépôts. C'est exactement
ce que fait Plumber —
scanner de conformité CI/CD qui couvre GitHub Actions et GitLab CI. Son
contrôle ISSUE-104 flagge toute action référencée par tag ou par SHA
non épinglé, soit précisément la surface d'attaque du tag poisoning :
# À la racine d'un dépôt GitHubplumber analyze --scoreSortie type sur un workflow vulnérable :
CRIT [ISSUE-104] Third-party actions must be pinned by commit SHA .github/workflows/issues.yml:12 actions-cool/issues-helper@v3 — référence mutable (tag)Bonus : Plumber maintient aussi une base de SHA d'actions porteuses de
CVE (contrôle ISSUE-703). Dès que les SHA imposteurs publiés par
StepSecurity remontent dans cette base, un workflow qui aurait épinglé par
erreur sur l'un d'eux serait également alerté. Lancez plumber analyze
dans une étape CI pour bloquer toute pull request qui régresse sur ces
contrôles — c'est exactement ce qui aurait empêché l'incident chez les
consommateurs disciplinés.
Indicateurs de compromission
Sur un runner compromis, vous trouverez :
- Présence du binaire
bundans/home/runner/.bun/bin/bunalors qu'il n'est pas attendu par votre workflow. - Lectures de
/proc/<PID>/memdepuis un processpython3enfant, avec des pipelinestr/grepqui filtrent sur"isSecret":true. - Connexion HTTPS sortante vers le domaine
t.m-kosche.comsur le port 443.
Ce domaine est désormais sur la liste de blocage globale de Harden-Runner. Si vous gérez votre propre liste d'allow-list réseau pour les runners, vous pouvez l'ajouter à vos règles de firewall sortant.
Pourquoi cette attaque répète le même pattern
C'est la troisième fois en deux mois qu'on observe le même mode
opératoire : un attaquant prend le contrôle d'un dépôt GitHub Actions,
réécrit tous les tags pour qu'ils pointent vers du code malveillant qui
vole les secrets via la mémoire de Runner.Worker. Avant actions-cool/,
il y a eu Trivy (deux fois) et KICS de
Checkmarx. Ce n'est plus un incident isolé, c'est un playbook
industrialisé.
La cible est toujours la même : les actions populaires qui s'exécutent avec les secrets de production et que les équipes consomment par tag, pas par SHA. La défense aussi est la même — et elle n'est pas négociable :
GitHub lui-même reconnaît le problème : la
roadmap sécurité GitHub Actions 2026
annonce un système de lock files de dépendances (équivalent
go.mod/go.sum pour les workflows) qui figera tous les SHAs directs
et transitifs. Public preview annoncée à 3-6 mois — en attendant, la
discipline manuelle reste la seule défense.
À retenir
- Tag poisoning : un attaquant qui contrôle un dépôt peut réécrire l'ensemble des tags pour pointer vers du code malveillant. Les utilisateurs pinned par tag récupèrent le payload à leur prochain run.
- Mémoire du Runner.Worker : c'est le process qui détient les secrets
déchiffrés. Lire
/proc/<PID>/memsuffit à les extraire — pas besoin de contourner GitHub Secrets. - L'épinglage par SHA légitime est la seule défense fiable et gratuite. Tout le reste (rotation, monitoring, allow-list) est un complément.
- Le pattern se répète : Trivy en mars, KICS en avril, actions-cool en
mai. Chaque mois, une nouvelle action populaire. Considérez que les
actions tierces de votre
.github/workflows/doivent être épinglées avant la prochaine vague — pas après. - Le lock file de workflow arrive côté GitHub natif courant 2026 : préparez vos workflows en pinned-SHA dès maintenant, vous gagnerez du temps à la migration.