Aller au contenu
CI/CD & Automatisation medium

Épingler les actions par SHA

14 min de lecture

Vous utilisez probablement des actions GitHub comme actions/checkout@v4 dans vos workflows. Ce @v4 semble anodin, mais c'est une faille de sécurité qui a déjà permis des attaques réelles. Ce guide vous explique pourquoi et comment vous protéger.

  • Comprendre le danger des tags mobiles (@v4, @main, @latest)
  • Reconnaître une attaque par déplacement de tag, façon tj-actions/changed-files
  • Épingler une action sur le SHA de son commit, avec commentaire de version
  • Trouver le SHA d'une action via l'API, la CLI ou l'interface GitHub
  • Automatiser la conversion et la mise à jour avec pin-github-action et Dependabot
  • Vérifier la couverture de l'épinglage sur l'ensemble d'un dépôt

Le suffixe @v4 que l'on voit partout dans les workflows désigne un tag Git. Derrière cette habitude anodine se cache une référence mobile — une faille structurelle que cette section décortique, d'abord par l'image, puis en termes techniques.

Imaginez que vous commandez toujours "le plat du jour" au restaurant. Hier, c'était un délicieux poulet rôti. Mais demain, sans vous prévenir, le chef pourrait le remplacer par quelque chose de toxique. Vous faites confiance au nom "plat du jour", pas au contenu réel.

C'est exactement ce qui se passe avec @v4 : vous faites confiance au nom du tag, mais son contenu peut changer à tout moment.

Un tag Git comme @v4 est simplement une étiquette qu'on colle sur un commit. Le problème ? Cette étiquette est mobile : n'importe qui ayant accès au dépôt peut la déplacer vers un autre commit.

SHA vs Tag : différence entre une étiquette mobile et une empreinte immuable

❌ Tag (@v4)

  • C'est une étiquette mobile
  • Peut pointer vers n'importe quel code
  • Modifiable par le mainteneur (ou un attaquant)

✅ SHA (empreinte)

  • C'est une empreinte cryptographique
  • Identifie un code précis et unique
  • Impossible à modifier ou falsifier

Ce n'est pas de la science-fiction. En mars 2025, l'action populaire tj-actions/changed-files a été compromise exactement de cette façon.

Chronologie d'une attaque par tag mutable

  1. Jour 1 : Vous utilisez action/exemple@v4 qui pointe vers le commit abc123 — du code légitime, testé et validé.

  2. Jour 30 : Un attaquant compromet le compte du mainteneur (phishing, mot de passe faible, token volé...).

  3. L'attaquant déplace le tag : @v4 pointe maintenant vers un nouveau commit xyz789 contenant du code malveillant.

  4. Jour 31 : Votre workflow se lance. Il récupère @v4... et exécute le code malveillant sans que vous ne remarquiez rien !

  5. Résultat : Vos secrets (GITHUB_TOKEN, clés API, credentials) sont exfiltrés vers l'attaquant.

Au lieu de faire confiance à une étiquette mobile, utilisez l'empreinte cryptographique (SHA) du commit. C'est comme donner l'empreinte digitale exacte du code que vous voulez exécuter.

# ❌ Dangereux : tag mutable — peut changer à tout moment
- uses: actions/checkout@v4
# ✅ Sécurisé : SHA immuable — toujours le même code
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

Pourquoi le commentaire # v4.2.2 ? Il indique à quelle version correspond ce SHA. C'est purement informatif pour vous (et Dependabot), mais c'est le SHA qui compte pour la sécurité.

Vous avez compris pourquoi utiliser un SHA. Maintenant, comment le trouver ? Plusieurs méthodes existent, de la plus simple à la plus automatisée.

La requête la plus directe interroge l'API REST de GitHub : elle renvoie le SHA du commit derrière n'importe quel tag, sans rien installer.

Fenêtre de terminal
# Obtenir le SHA du tag v4.2.2 de l'action checkout
curl -s https://api.github.com/repos/actions/checkout/commits/v4.2.2 \
| jq -r .sha

Résultat attendu : 11bd71901bbe5b1630ceea73d27597364c9af683

Si la CLI gh est installée et authentifiée, un seul appel suffit : elle gère l'authentification et l'extraction du SHA sans curl ni jq.

Fenêtre de terminal
gh api repos/actions/checkout/commits/v4.2.2 --jq .sha

Sans terminal, l'interface GitHub donne le SHA en quelques clics depuis la page des releases du dépôt.

  1. Allez sur le dépôt de l'action (ex: github.com/actions/checkout)
  2. Cliquez sur l'onglet Releases dans la barre latérale
  3. Trouvez la version souhaitée (ex: v4.2.2)
  4. Cliquez sur le lien du commit associé
  5. Copiez le SHA complet (40 caractères) depuis l'URL ou la page

Automatiser l'épinglage (ne le faites pas à la main !)

Section intitulée « Automatiser l'épinglage (ne le faites pas à la main !) »

Convertir manuellement chaque action serait fastidieux et source d'erreurs. Heureusement, des outils font le travail pour vous.

Option 1 : pin-github-action (en ligne de commande)

Section intitulée « Option 1 : pin-github-action (en ligne de commande) »

Cet outil analyse vos workflows et remplace automatiquement les tags par leurs SHA :

Fenêtre de terminal
# Installer l'outil
npm install -g pin-github-action
# Convertir un seul workflow
pin-github-action .github/workflows/ci.yml
# Convertir TOUS les workflows d'un coup
find .github/workflows -name "*.yml" -exec pin-github-action {} \;

Avant (vulnérable) :

- uses: actions/checkout@v4
- uses: actions/setup-node@v4

Après (sécurisé) :

- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0

Si vous préférez une interface graphique, app.stepsecurity.io offre une solution simple :

  1. Collez votre workflow YAML dans l'interface
  2. L'outil convertit automatiquement tous les tags en SHA
  3. Copiez le résultat sécurisé
  4. Remplacez votre fichier workflow

Bonus : StepSecurity analyse aussi d'autres aspects de sécurité de vos workflows (permissions, secrets exposés, etc.).

Un SHA épinglé, c'est bien. Mais les actions reçoivent des mises à jour de sécurité et des nouvelles fonctionnalités. Comment rester à jour sans revenir aux tags mutables ?

Dependabot surveille vos dépendances et crée automatiquement des Pull Requests quand de nouvelles versions sont disponibles :

.github/dependabot.yml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly" # Vérifie chaque semaine
commit-message:
prefix: "ci" # Préfixe des commits : "ci: ..."

Comment ça marche : Dependabot détecte le commentaire # v4.2.2 dans vos workflows. Quand v4.2.3 sort, il crée une PR qui met à jour le SHA et le commentaire. Vous n'avez qu'à review et merger !

Renovate est une alternative à Dependabot avec plus d'options de configuration :

renovate.json
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"github-actions": {
"enabled": true,
"pinDigests": true
}
}

Comment savoir si vos workflows sont correctement sécurisés ? L'outil Scorecard de l'OpenSSF analyse votre dépôt et note vos pratiques de sécurité :

Fenêtre de terminal
scorecard --local . --checks Pinned-Dependencies --show-details

Interprétation du score :

ScoreSignification
10/10Parfait ! Toutes les actions sont épinglées par SHA
5-9/10Certaines actions utilisent encore des tags
0/10Danger ! Tags mutables partout (@v1, @latest, @main)

Les actions GitHub officielles, on les épingle aussi ?

Section intitulée « Les actions GitHub officielles, on les épingle aussi ? »

Oui ! Même si les actions maintenues par GitHub (actions/*) sont plus fiables que les actions tierces, l'épinglage reste une bonne pratique :

ActionUsagePourquoi l'épingler
actions/checkoutCloner le repoA accès à votre code source
actions/setup-nodeInstaller Node.jsExécute des scripts sur le runner
actions/setup-pythonInstaller PythonIdem
actions/cacheCache des dépendancesManipule des fichiers
actions/upload-artifactSauvegarder des artifactsA accès aux fichiers produits
actions/download-artifactRécupérer des artifactsPeut injecter des fichiers

Le principe : tout code qui s'exécute dans votre CI mérite d'être vérifié et épinglé, quelle que soit sa source.

Toutes les actions ne se valent pas. Avant d'ajouter une action tierce à vos workflows, posez-vous ces questions :

✅ Signaux positifs

  • Beaucoup d'étoiles et d'utilisateurs
  • Commits réguliers, issues traitées
  • Maintenue par une organisation connue
  • Code source lisible et documenté
  • Releases avec changelog

⚠️ Signaux d'alerte

  • Peu d'étoiles, pas de maintenance
  • Demande permissions: write-all
  • Pas de releases tagguées
  • Code obfusqué ou minifié
  • Maintenue par un compte anonyme

Voici un workflow qui applique toutes les bonnes pratiques :

.github/workflows/ci.yml
name: CI
# Aucune permission par défaut : chaque job demande ce qu'il lui faut
permissions: {}
on:
push:
branches: [main]
pull_request:
jobs:
build:
runs-on: ubuntu-24.04
permissions:
contents: read
steps:
# Toutes les actions sont épinglées par SHA
- name: Récupérer le code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Installer Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '20'
cache: 'npm'
- name: Installer les dépendances
run: npm ci
- name: Lancer les tests
run: npm test
- name: Publier la couverture
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: coverage
path: coverage/

Ce qui rend ce workflow sécurisé :

  1. permissions: {} au niveau workflow, contents: read accordé au seul job qui en a besoin
  2. Toutes les actions épinglées par SHA, avec commentaire de version
  3. persist-credentials: false sur actions/checkout — le GITHUB_TOKEN ne reste pas dans la config git
  4. Commentaires de version exploités par Dependabot
  5. Aucune action tierce douteuse

Récapitulatif : les 3 étapes pour sécuriser vos workflows

Section intitulée « Récapitulatif : les 3 étapes pour sécuriser vos workflows »

Trois actions concrètes suffisent à passer d'un dépôt vulnérable à des workflows épinglés et maintenus.

  1. Convertir tous vos workflows avec pin-github-action ou StepSecurity

  2. Configurer Dependabot pour garder les SHA à jour automatiquement

  3. Vérifier régulièrement avec Scorecard que rien n'a été oublié

  • Un tag Git (@v4, @main, @latest) est une référence mobile : le mainteneur — ou un attaquant — peut la déplacer vers n'importe quel code.
  • L'attaque tj-actions/changed-files de mars 2025 a exploité exactement ce mécanisme pour exfiltrer les secrets de milliers de pipelines.
  • Épingler une action sur le SHA de commit (40 caractères) garantit que le pipeline exécute toujours le même code vérifié.
  • Le commentaire # v4.2.2 après le SHA est informatif : il permet à Dependabot de proposer les mises à jour de version.
  • On n'épingle pas à la main : pin-github-action ou StepSecurity convertissent les workflows, Dependabot ou Renovate maintiennent les SHA à jour.
  • Les actions officielles actions/* s'épinglent aussi — tout code exécuté dans la CI mérite d'être figé.

Côté outils : pin-github-action pour l'épinglage en ligne de commande, et StepSecurity pour une plateforme de sécurité CI/CD complète.

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn