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 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 le code |
| 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 700 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 volé un PAT (Personal Access Token) du mainteneur, puis a réécrit les tags existants pour pointer vers du code malveillant qui exfiltrait tous les secrets dans les logs publics du workflow.
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 repos infiltrés, 3 325 secrets volés. Les
attaquants ont exploité des workflows utilisant pull_request_target avec
des permissions trop larges pour obtenir un accès en écriture. Les secrets
volés (clés AWS, tokens PyPI et npm) étaient envoyés vers des serveurs
contrôlés par les attaquants.
Vecteurs exploités :
pull_request_targetavec checkout du code de la PRGITHUB_TOKENavec permissionswritepar défaut- Pas de contrôle des connexions réseau sortantes
Shai Hulud v2 — novembre 2025
Section intitulée « Shai Hulud v2 — novembre 2025 »Le premier ver auto-réplicant à grande échelle sur GitHub Actions. 20 000+
dépôts infectés, 1 700 versions npm compromises. Le ver exploitait
pull_request_target pour obtenir un token write, puis s’injectait dans le
code du dépôt cible. Depuis ce dépôt infecté, il ouvrait des PR vers d’autres
dépôts et se propageait de manière exponentielle.
Vecteurs exploités :
pull_request_target+ checkout du code du forkGITHUB_TOKENaveccontents: write- Tokens d’organisation à portée large
- Absence de contrôle réseau (exfiltration libre)
hackerbot-claw / Trivy — février 2026
Section intitulée « hackerbot-claw / Trivy — février 2026 »Un bot IA autonome qui a ciblé 6 dépôts majeurs de l’écosystème
open-source entre le 21 et le 28 février 2026. Le bot identifiait
automatiquement les workflows vulnérables, créait des PRs malveillantes, et
exploitait pull_request_target pour obtenir une exécution de code avec les
privilèges du dépôt cible.
Sur Trivy, l’attaque a conduit au vidage complet du dépôt GitHub et à la suppression de toutes les releases de la v0.27.0 à la v0.69.1.
Vecteurs exploités :
pull_request_targetsans garde-fousGITHUB_TOKENavec permissions d’écriture- Workflow qui exécutait du code provenant du fork
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 »En analysant ces attaques, 5 vecteurs reviennent systématiquement. Les corriger bloque la quasi-totalité des attaques connues.
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-latest 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 repo
# ✅ 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-latest permissions: contents: read steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - 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 (en cours d’écriture).
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-latest permissions: contents: read # Seulement ce qui est nécessaire steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - run: npm test
publish: needs: test runs-on: ubuntu-latest permissions: contents: read packages: write # Write uniquement pour le job qui publie steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - run: npm publishGuide détaillé : Permissions GitHub Actions (en cours d’écriture).
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.
L’attaque Gluestack/gluestack-ui (juin 2025) exploitait exactement ce vecteur :
une commande malveillante injectée via la page de discussions du dépôt,
déclenchée par un workflow qui incorporait des inputs non validés dans un bloc
run:.
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@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.10.2 with: egress-policy: audit # D'abord observer, puis bloquer
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - 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@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6with: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 1 — Prévention (shift left) ││ actionlint, poutine, Semgrep, pre-commit │├─────────────────────────────────────────────┤│ Couche 2 — Configuration ││ permissions: {}, SHA pinning, OIDC │├─────────────────────────────────────────────┤│ Couche 3 — Détection ││ Harden Runner, Gitleaks, Scorecard │├─────────────────────────────────────────────┤│ Couche 4 — Confinement ││ egress: block, runners éphémères, env gate │├─────────────────────────────────────────────┤│ Couche 5 — Réponse ││ 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 »Intégrez des linters et scanners dans vos hooks pre-commit et votre CI :
| Outil | Ce qu’il détecte |
|---|---|
| actionlint | Erreurs de syntaxe, patterns dangereux |
| 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 :
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 »- 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 »- 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 »- 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.
À retenir
Section intitulée « À retenir »Les attaques supply chain sur GitHub Actions exploitent toujours les mêmes
5 vecteurs : pull_request_target mal sécurisé, tags mutables, permissions
excessives, injection de commandes et exfiltration réseau non contrôlée.
Les attaques de 2025-2026 (Shai Hulud v2, GhostAction, tj-actions, hackerbot-claw) montrent que ces failles sont activement exploitées à grande échelle, y compris par des bots IA autonomes.
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é.