Ce guide vous permet de comprendre et de bloquer les attaques supply chain qui ont compromis des dizaines de milliers de dépôts en 2025-2026 via GitHub Actions. Vous apprendrez à reconnaître les vecteurs d'exploitation, à auditer vos workflows existants, et à déployer une défense en profondeur. Prérequis : connaître les bases de GitHub Actions et avoir lu le guide Sécurité GitHub Actions.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Reconnaître les 5 vecteurs d'attaque exploités contre GitHub Actions
- Décortiquer les attaques réelles 2025-2026 : tj-actions, GhostAction, Shai Hulud v2, hackerbot-claw
- Auditer un dépôt existant à la recherche de configurations vulnérables
- Corriger chaque vecteur :
pull_request_target, tags mutables, permissions, injection, exfiltration - Déployer une défense en profondeur sur cinq couches complémentaires
Ce que vous risquez concrètement
Section intitulée « Ce que vous risquez concrètement »Un workflow GitHub Actions mal configuré donne à un attaquant un accès privilégié à toute votre chaîne de livraison. Ce n'est pas théorique : en 2025, des attaques réelles ont exploité ces failles pour voler des secrets, injecter du code malveillant et compromettre des packages distribués à des milliers d'utilisateurs.
Voici ce qu'un attaquant peut obtenir en compromettant un seul workflow :
| Ressource | Impact | Cas réel |
|---|---|---|
| Secrets (tokens, credentials) | Vol et réutilisation pour accéder à vos systèmes cloud, registres, APIs | GhostAction : 3 325 secrets volés (AWS, PyPI, npm) |
| Code source | Injection de backdoors invisibles dans le code | Shai Hulud v2 : ver qui se réplique dans les paquets publiés |
| Artefacts (images, binaires) | Distribution de malware à vos utilisateurs | Nx s1ngularity : packages npm infectés |
| Registres (npm, Docker Hub) | Publication de versions compromises sous votre nom | 1 092 versions npm infectées par Shai Hulud v2 |
| Production | Déploiement de code malveillant | Accès cloud via tokens volés |
Anatomie des attaques 2025-2026
Section intitulée « Anatomie des attaques 2025-2026 »tj-actions/changed-files, mars 2025
Section intitulée « tj-actions/changed-files, mars 2025 »L'action la plus populaire pour détecter les fichiers modifiés (23 000+
dépôts). Un attaquant a obtenu le PAT (Personal Access Token) d'un bot
disposant d'un accès en écriture au dépôt, très probablement à la faveur de la
compromission d'une autre action, reviewdog/action-setup (CVE-2025-30154).
Il a ensuite réécrit les tags existants, de v1 à v45.0.7, pour les
faire pointer vers un commit malveillant qui exfiltrait tous les secrets
dans les logs publics du workflow. L'incident est suivi sous la référence
CVE-2025-30066.
Vecteurs exploités :
- Tags Git mutables (les utilisateurs faisaient confiance à
@v1) - Pas d'épinglage par SHA
- Secrets visibles dans les logs de workflow
Leçon : un tag @v1 n'est qu'une étiquette mobile. Seul un SHA garantit
que le code exécuté est celui que vous avez validé.
GhostAction, septembre 2025
Section intitulée « GhostAction, septembre 2025 »327 comptes compromis, 817 dépôts infiltrés, 3 325 secrets volés. Le mode opératoire ne repose sur aucune faille de workflow : les attaquants ont d'abord pris le contrôle de comptes de mainteneurs, puis lu les workflows légitimes pour inventorier les noms des secrets disponibles dans chaque dépôt. Ils ont ensuite commité un workflow malveillant maquillé en « Github Actions Security », qui recopiait ces secrets nommément et les envoyait par requête HTTP POST vers un point de collecte. Les identifiants volés couvraient des clés AWS, des tokens PyPI, npm, DockerHub et GitHub.
Vecteurs exploités :
- Compromission de compte de mainteneur (pas de second facteur robuste)
- Absence de protection de branche sur
.github/workflows/ - Aucune revue obligatoire sur l'ajout d'un fichier de workflow
- Pas de contrôle des connexions réseau sortantes du runner
Shai Hulud v2, novembre 2025
Section intitulée « Shai Hulud v2, novembre 2025 »Un ver auto-réplicant à grande échelle sur l'écosystème npm. L'analyse de
Datadog recense 796 paquets npm uniques porteurs du ver, soit 1 092
versions publiées, et plus de 14 000 dépôts GitHub créés pour
l'exfiltration ; d'autres décomptes montent au-delà de 25 000 dépôts. La
propagation ne passe pas par les workflows : le ver injecte deux fichiers
(setup_bun.js et bun_environment.js) déclenchés par un script
preinstall, moissonne les identifiants présents sur la machine, puis
utilise les tokens npm volés pour republier automatiquement d'autres
paquets piégés avec npm publish.
Le lien avec GitHub Actions est réel mais indirect. Sur les machines
compromises, le ver installe un runner self-hosted et y déploie une action
volontairement vulnérable : l'attaquant reprend ensuite la main en ouvrant une
GitHub Discussion contenant les commandes à exécuter, ce qui lui donne un
canal de commande et contrôle sans serveur externe. Le ver injecte également
un workflow shai-hulud-workflow.yml qui exfiltre les secrets à chaque push.
Vecteurs exploités :
- Scripts
preinstallnpm exécutés sans bac à sable à l'installation - Tokens npm et PAT GitHub longue durée stockés en clair sur les postes
- Enregistrement d'un runner self-hosted non maîtrisé
- Absence de contrôle réseau (exfiltration libre)
hackerbot-claw / Trivy, février-mars 2026
Section intitulée « hackerbot-claw / Trivy, février-mars 2026 »Un bot IA autonome qui a ciblé 7 dépôts majeurs de l'écosystème
open-source entre le 20 février et le 2 mars 2026. Le bot identifiait
automatiquement les workflows vulnérables, créait des pull requests
malveillantes, et exploitait selon les cibles soit pull_request_target avec
checkout du fork, soit une injection de commande via le nom de branche ou
un nom de fichier. Chaque exploitation livrait le même payload distant.
Sur Trivy, l'attaque a conduit au vol du PAT d'un mainteneur, puis au vidage complet du dépôt GitHub et à la suppression de toutes les releases de la v0.27.0 à la v0.69.1 dans la nuit du 1er mars 2026.
Vecteurs exploités :
pull_request_targetsans garde-fousGITHUB_TOKENavec permissions d'écriture- Workflow qui exécutait du code provenant du fork
- Interpolation
${{ }}de noms de branche et de fichiers dans un blocrun: - Absence de contrôle
author_associationsur les commandes en commentaire
Pour le récit complet de l'incident, voir le billet Trivy vidé après une attaque supply chain par un bot IA.
Les 5 vecteurs d'attaque principaux
Section intitulée « Les 5 vecteurs d'attaque principaux »Ces quatre incidents n'ont pas le même point d'entrée : deux passent par un workflow vulnérable, deux par un identifiant volé. Mais tous franchissent ensuite les mêmes portes, et ce sont ces 5 vecteurs que vous pouvez fermer dans vos propres dépôts. Les corriger ne rend pas invulnérable à un vol de PAT, mais supprime la quasi-totalité de la surface exploitable depuis l'extérieur et limite fortement ce qu'un identifiant volé permet d'obtenir.
Vecteur 1, La Pwn Request (pull_request_target)
Section intitulée « Vecteur 1, La Pwn Request (pull_request_target) »C'est le vecteur le plus dévastateur. L'événement pull_request_target
a été conçu pour permettre aux mainteneurs de réagir aux PRs de forks avec
accès aux secrets (par exemple, pour labelliser). Le problème : il exécute
le workflow dans le contexte du dépôt cible, avec ses secrets et un
GITHUB_TOKEN potentiellement en écriture.
| Événement | Code exécuté | Accès aux secrets | Risque |
|---|---|---|---|
pull_request | Code du fork | Non (forks) | Faible |
pull_request_target | Code de la branche cible | Oui | Critique si checkout du fork |
Le scénario d'exploitation :
-
L'attaquant fork le dépôt cible
-
Il modifie un script (build, test, linter) pour injecter du code malveillant
-
Il ouvre une PR, ce qui déclenche
pull_request_target -
Le workflow checkout le code de la PR (
ref: ${{ github.event.pull_request.head.sha }}) et l'exécute avec les privilèges du dépôt cible -
Le code malveillant exfiltre les secrets, modifie le code, ou se propage
Comment se protéger :
# ❌ DANGEREUX : checkout du code du fork avec accès aux secretson: pull_request_target:jobs: test: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ github.event.pull_request.head.sha }} - run: npm test # Exécute le code du fork avec les secrets du repoLa version sûre bascule sur pull_request : les forks n'ont alors aucun
accès aux secrets.
# ✅ SÉCURISÉ : utiliser pull_request (pas d'accès aux secrets pour les forks)on: pull_request: types: [opened, synchronize]jobs: test: runs-on: ubuntu-24.04 permissions: contents: read steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - run: npm testSi vous avez absolument besoin de pull_request_target (rare), appliquez
ces garde-fous :
- Ne faites jamais de checkout du code de la PR
- Ajoutez une condition
ifrestrictive (label spécifique, auteur autorisé) - Limitez les permissions au strict minimum
Guide détaillé : Sécuriser pull_request_target.
Vecteur 2, Tags mutables et supply chain des actions
Section intitulée « Vecteur 2, Tags mutables et supply chain des actions »Quand vous écrivez uses: some/action@v1, GitHub résout le tag vers un
commit. Mais un tag est une étiquette mobile : le mainteneur (ou un
attaquant) peut le déplacer vers n'importe quel commit à tout moment.
C'est le mécanisme exact exploité par tj-actions/changed-files : les tags
@v1, @v2, etc. ont été réécrits pour pointer vers du code qui exfiltrait
les secrets.
Comment se protéger :
# ❌ Tag mutable : le contenu peut changer sans préavis- uses: actions/checkout@v4
# ❌ Version précise, mais le tag reste mutable- uses: actions/checkout@v4.2.2
# ✅ SHA complet : immuable et vérifiable- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2-
Convertir tous vos tags en SHA
Utilisez StepSecurity (interface web) ou l'outil CLI :
Fenêtre de terminal npm install -g pin-github-actionpin-github-action .github/workflows/ci.yml -
Activer Dependabot pour les mises à jour automatiques
.github/dependabot.yml version: 2updates:- package-ecosystem: "github-actions"directory: "/"schedule:interval: "weekly" -
Auditer avec Scorecard
Fenêtre de terminal scorecard --local . --checks Pinned-Dependencies --show-details
Guide détaillé : Épingler les actions par SHA.
Vecteur 3, Permissions GITHUB_TOKEN excessives
Section intitulée « Vecteur 3, Permissions GITHUB_TOKEN excessives »Le GITHUB_TOKEN est généré automatiquement pour chaque workflow. Avec des
permissions trop larges, un workflow compromis peut modifier le code source,
créer des releases, publier des packages, et persister dans le dépôt.
C'est un accélérateur de toutes les autres attaques. Comme le souligne
l'analyse d'Arctiq,
combiné avec pull_request_target, c'est une "combinaison explosive" utilisée
par Shai Hulud v2 et GhostAction.
Comment se protéger :
# Permissions zéro par défaut au niveau workflowpermissions: {}
jobs: test: runs-on: ubuntu-24.04 permissions: contents: read # Seulement ce qui est nécessaire steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - run: npm test
publish: needs: test runs-on: ubuntu-24.04 permissions: contents: read packages: write # Write uniquement pour le job qui publie steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - run: npm publishGuide détaillé : Permissions GitHub Actions.
Vecteur 4, Injection de commandes
Section intitulée « Vecteur 4, Injection de commandes »L'interpolation ${{ }} dans un bloc run: se fait avant l'exécution du
shell, sans échappement. Un attaquant qui contrôle un titre de PR, un nom de
branche ou un corps d'issue peut injecter du code arbitraire.
La faille CVE-2025-53104 de gluestack/gluestack-ui, publiée en juin 2025,
illustre exactement ce vecteur : le workflow discussion-to-slack.yml
interpolait le titre et le corps d'une GitHub Discussion dans un bloc
run:, ce qui permettait à n'importe qui d'exécuter du code sur le runner en
ouvrant une discussion contenant $(...). Elle a été découverte en marge
d'un incident distinct, la compromission des paquets npm du projet, qui
provenait elle du vol du PAT d'un développeur. Le workflow vulnérable a
été supprimé.
Données dangereuses (ne jamais interpoler directement) :
| Source | Variable |
|---|---|
| Titre de PR | github.event.pull_request.title |
| Corps de PR | github.event.pull_request.body |
| Titre d'issue | github.event.issue.title |
| Commentaire | github.event.comment.body |
| Nom de branche | github.event.pull_request.head.ref |
| Message de commit | github.event.head_commit.message |
| Input dispatch | github.event.inputs.* |
Comment se protéger :
# ❌ Injection possible- run: echo "PR: ${{ github.event.pull_request.title }}"
# ✅ Variable d'environnement : le shell traite la valeur comme une chaîne- run: echo "PR: $PR_TITLE" env: PR_TITLE: ${{ github.event.pull_request.title }}Vecteur 5, Exfiltration réseau non contrôlée
Section intitulée « Vecteur 5, Exfiltration réseau non contrôlée »Tous les vecteurs précédents ont besoin d'un canal de sortie pour envoyer les secrets volés. Si vous bloquez les connexions réseau sortantes, même un workflow compromis ne peut pas exfiltrer vos données.
Comment se protéger :
steps: # DOIT être la première étape du job - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit # D'abord observer, puis bloquer
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - run: npm ci && npm test-
Déployer en mode
auditpour observer les connexions légitimes -
Analyser le tableau de bord StepSecurity (lien dans les logs du job)
-
Passer en mode
blockavec la liste des endpoints autorisés- uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0with:egress-policy: blockallowed-endpoints: >github.com:443registry.npmjs.org:443objects.githubusercontent.com:443
Stratégie de défense en profondeur
Section intitulée « Stratégie de défense en profondeur »Aucune mesure isolée ne suffit. La sécurité de vos workflows repose sur la combinaison de plusieurs couches de protection :
| Couche | Objectif | Outils et mesures |
|---|---|---|
| 1, Prévention | Détecter les problèmes avant le commit | actionlint, zizmor, poutine, Semgrep |
| 2, Configuration | Réduire la surface d'attaque | permissions: {}, épinglage SHA, OIDC |
| 3, Détection | Surveiller pendant l'exécution | Harden Runner, Gitleaks, Scorecard |
| 4, Confinement | Limiter le rayon d'explosion | egress: block, runners éphémères, environnements gatés |
| 5, Réponse | Se préparer au pire | Rotation des secrets, audit logs, SIEM |
Couche 1, Prévention : détecter les problèmes avant le commit
Section intitulée « Couche 1, Prévention : détecter les problèmes avant le commit »Cette couche est la moins coûteuse et celle qui rend le plus : elle refuse un
workflow dangereux avant qu'il n'existe en production. Les quatre premiers
outils du tableau ne se remplacent pas les uns les autres, ils ont des
angles distincts. actionlint valide la syntaxe et les expressions,
zizmor raisonne sur la sécurité du workflow lui-même, poutine couvre
plusieurs plateformes de CI et repère les schémas propres aux pipelines,
Semgrep porte vos règles maison. Enchaînez-les dans le même job, chacun
échouant indépendamment, plutôt que d'en choisir un.
| Outil | Ce qu'il détecte |
|---|---|
| actionlint | Erreurs de syntaxe, patterns dangereux |
| zizmor | Audit de sécurité statique des workflows |
| poutine | Vulnérabilités spécifiques GitHub Actions |
| Semgrep | Règles custom (ban pull_request_target, etc.) |
| Checkov | Mauvaises pratiques dans les workflows |
Couche 2, Configuration : réduire la surface d'attaque
Section intitulée « Couche 2, Configuration : réduire la surface d'attaque »Ce sont les mesures décrites dans les 5 vecteurs ci-dessus. Elles ne demandent aucun outil supplémentaire, seulement de la rigueur dans le YAML, et elles ont un effet cumulatif : chacune retire une capacité à un attaquant qui aurait déjà pris pied dans le pipeline. La plus rentable des quatre est OIDC, qui supprime la catégorie entière des identifiants cloud volables.
permissions: {}au niveau workflow- Épinglage SHA systématique
- OIDC pour les déploiements cloud
- Secrets scopés par step et environnement
Couche 3, Détection : surveiller en temps réel
Section intitulée « Couche 3, Détection : surveiller en temps réel »Les deux couches précédentes supposent que vous avez pensé à tout. Celle-ci part du principe inverse et cherche les écarts au comportement attendu pendant que le job tourne. Elle a un coût de mise en route : chaque outil produit du bruit tant que la ligne de base n'est pas établie. Commencez par Harden Runner en mode observation, laissez tourner deux semaines, et vous disposerez de la liste des destinations réseau réellement utilisées par vos pipelines. C'est cette liste qui rend la couche 4 applicable.
- Harden Runner : surveille les connexions réseau pendant l'exécution
- Gitleaks / TruffleHog : scan continu des commits pour les secrets
- Scorecard : audit périodique de la posture sécurité
Couche 4, Confinement : limiter le rayon d'explosion
Section intitulée « Couche 4, Confinement : limiter le rayon d'explosion »Le confinement ne cherche pas à empêcher la compromission mais à la rendre stérile. Un attaquant qui exécute du code sur un runner sans sortie réseau autorisée et détruit après le job repart sans rien. Ces trois mesures se posent dans cet ordre : le blocage réseau d'abord, parce qu'il coupe l'exfiltration, source de valeur de la quasi-totalité des attaques recensées plus haut ; l'approbation manuelle en dernier, parce qu'elle coûte du temps humain à chaque déploiement.
- egress: block : empêcher l'exfiltration réseau
- Runners éphémères : pas de persistance entre les jobs
- Environnements avec approbation : gate humain avant la production
Couche 5, Réponse : se préparer au pire
Section intitulée « Couche 5, Réponse : se préparer au pire »Cette couche se juge à une question : combien de temps vous faut-il pour révoquer et remplacer tous les secrets d'un dépôt ? Si la réponse dépasse l'heure ou si personne ne la connaît, vous n'avez pas de plan de réponse. Les attaques de 2025-2026 montrent que la fenêtre utile est courte, l'exfiltration des secrets Trivy et leur exploitation ont tenu dans la même nuit. Écrivez la procédure de rotation, testez-la une fois, et gardez les journaux d'audit ailleurs que dans le dépôt compromis.
- Rotation des secrets : procédure documentée et testée
- Audit logs : centraliser dans un SIEM pour investigation
- Dependabot : alertes automatiques sur les actions vulnérables
Plan d'action en 5 étapes
Section intitulée « Plan d'action en 5 étapes »Si vous partez de zéro, voici par où commencer :
-
Auditer vos workflows existants
Fenêtre de terminal # Lister tous les workflowsfind .github/workflows -name '*.yml' -o -name '*.yaml'# Chercher les patterns dangereuxgrep -rn 'pull_request_target' .github/workflows/grep -rn 'permissions:.*write-all' .github/workflows/grep -rn '\${{.*github\.event\.' .github/workflows/grep -rn '@v[0-9]' .github/workflows/# Audit complet avec Scorecardscorecard --local . --format json | jq '.checks[] | {name, score}' -
Corriger les failles critiques en priorité
- Supprimer tout
pull_request_targetavec checkout du fork - Ajouter
permissions: {}à chaque workflow - Remplacer
${{ github.event.* }}dans lesrun:par desenv:
- Supprimer tout
-
Épingler toutes les actions par SHA
Fenêtre de terminal npm install -g pin-github-actionfind .github/workflows -name '*.yml' -exec pin-github-action {} \; -
Ajouter Harden Runner et Gitleaks
Déployer Harden Runner en mode
auditsur tous les jobs, et Gitleaks pour bloquer le merge si un secret est détecté. -
Mettre en place le suivi continu
Activer Dependabot pour
github-actions, planifier un audit Scorecard mensuel, et configurer les alertes dans votre SIEM.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »Les attaques supply chain sur GitHub Actions se ramènent à 5 vecteurs :
pull_request_target mal sécurisé, tags mutables, permissions excessives,
injection de commandes et exfiltration réseau non contrôlée. Ce sont les cinq
portes que vous contrôlez dans vos dépôts.
Les incidents de 2025-2026 se répartissent en deux familles. tj-actions et
hackerbot-claw partent d'une faiblesse du workflow et sont donc évitables
par les cinq corrections ci-dessus. GhostAction et Shai Hulud v2 partent d'un
identifiant volé, compte de mainteneur ou token npm : contre eux, les
mesures utiles sont l'authentification forte, les identifiants éphémères
(OIDC) et la protection des fichiers de workflow par revue obligatoire.
La bonne nouvelle : corriger ces 5 vecteurs ne nécessite pas d'outils sophistiqués. C'est une question de discipline, permissions minimales, SHA partout, inputs jamais interpolés, secrets isolés, réseau surveillé.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Scanner avec poutine : Détecter les vecteurs décrits ici sur tous vos dépôts, sans relecture manuelle.
- Permissions du GITHUB_TOKEN : Réduire ce qu'un attaquant obtient une fois le workflow compromis.
- Sécuriser pull_request_target : Neutraliser le déclencheur qui offre les secrets du dépôt au code d'un fork.
- Checklist sécurité : Le récapitulatif à passer sur chaque workflow déjà en production.