GitHub Actions a reçu un lockfile le 14 octobre. Il fige le code que tu as relu. Il ne le relit pas.

Le mercredi 14 octobre, GitHub a mis en préversion publique les lockfiles de dépendances de workflows pour GitHub Actions, sur les forfaits Enterprise Cloud (avec ou sans résidence des données), Team et Free. Un fichier .github/workflows/actions.lock, généré par une extension de la CLI GitHub appelée gh actions-lock, enregistre le commit exact derrière chaque action qu'un workflow utilise, y compris les actions que ces actions appellent, et les workflows réutilisables dont il dépend. Une fois un workflow intégré, GitHub Actions exécute les commits enregistrés, même si un tag ou une branche bouge. Une politique associée, Require lockfile, permet aux administrateurs d'entreprise, d'organisation et de dépôt de la rendre obligatoire.
L'annonce est courte. Les docs, le README de l'extension et la discussion de conception qui l'a précédée ne le sont pas, et ils contiennent les passages qui décident si cela te protège ou ajoute simplement un fichier à ton dépôt.
Je suis CTO d'une LegalTech construite sur Claude, et je livre des applications iOS et un jeu de stratégie en développeur indépendant. Des produits différents, la même question : un job de CI qui détient des secrets exécute chaque étape tierce juste à côté d'eux. Alors j'ai tout lu.
Pourquoi un tag est le point faible
Quand un workflow dit uses: some-org/some-action@v3, Actions résout v3 vers le commit sur lequel le tag pointe au démarrage du job. Les tags peuvent être déplacés. Toute l'attaque tient là.
En mars 2025, des attaquants ont « modifié rétroactivement plusieurs tags de version » de tj-actions/changed-files pour qu'ils pointent vers un commit malveillant, selon sa fiche dans la GitHub Advisory Database, qui date l'exposition des 14 et 15 mars et chiffre l'impact à plus de 23 000 dépôts. La charge utile lisait les secrets dans la mémoire du runner et les imprimait dans les journaux de build.
Le 19 mars 2026, c'est reparti. La chronologie d'Aqua Security indique qu'un attaquant a forcé le push de 76 des 77 tags de version de aquasecurity/trivy-action vers des commits malveillants (les premiers décomptes extérieurs, de Socket et Snyk, parlaient de 75 sur 76). Les pipelines ont continué à tourner, écrit Aqua, « sans aucune indication que le code sous-jacent avait changé ».
Une semaine plus tard, le 26 mars, GitHub a publié sa feuille de route de sécurité 2026 pour Actions. Elle citait tj-actions/changed-files, Nx et trivy-action, et fixait un objectif de trois à six mois pour une préversion publique du verrouillage des dépendances. Elle est arrivée six mois et 18 jours plus tard.
Ce que le fichier enregistre
Les docs décrivent deux sections. workflows liste les dépendances de chaque workflow intégré. dependencies liste, pour chacune, le ref que tu as écrit (un tag ou une branche), le commit vers lequel il a été résolu, et les owner_id et repo_id numériques du dépôt source.
Trois détails comptent plus que l'épinglage lui-même.
Le commit verrouillé doit exister dans une branche du dépôt source. Le README dit que c'est « pour rendre plus difficiles les attaques par commit imposteur ». La discussion de conception de GitHub l'avait posé en mai : un simple épinglage par SHA dans un fichier de workflow ne garantit pas que le commit vit dans le dépôt nommé plutôt que dans un fork contrôlé par un attaquant.
L'identité du dépôt est vérifiée au démarrage du job. D'après le README, le runner confirme que le dépôt n'a pas été renommé ni transféré, que le commit épinglé existe toujours, et qu'un tag de version complet comme v4.2.1 pointe toujours dessus. Une vérification qui échoue bloque l'exécution.
Et les actions composites ne cachent plus leurs propres lignes uses:, parce que les dépendances transitives sont épinglées aussi.
Pour les dépôts qui adoptent un lockfile, GitHub dit désormais que l'épinglage par SHA dans les fichiers de workflow « n'est plus nécessaire ».
Le design livré n'est pas celui que GitHub avait d'abord proposé. La feuille de route de mars décrivait une section dependencies: dans le YAML du workflow, résolue via la CLI GitHub, et la discussion de mai nommait la commande qui l'écrirait, gh actions pin. Ce qui est sorti, c'est un fichier séparé par dépôt, maintenu par une extension. Je pense que c'est le meilleur choix : un seul fichier à comparer, un seul chemin à protéger.
Ce que l'annonce ne dit pas
L'extension modifie plus que le lockfile. Elle réécrit les références vers la version précise qu'elle a résolue, si bien que @v3 peut devenir @v3.1.0, et elle convertit les actions du même dépôt en ./… vers une nouvelle syntaxe $/… qui se résout toujours vers le commit en cours d'exécution. Relis le diff en entier, pas seulement le nouveau fichier.
Si ton organisation restreint les actions autorisées, vérifie la liste d'autorisation avant de committer. Après l'intégration, la liste est comparée aux SHA de commit verrouillés, et les entrées épinglées sur un tag, comme actions/checkout@v6, « ne correspondent plus ». Les docs disent d'utiliser un joker ou le SHA complet.
Les workflows réutilisables sont une frontière. Ton lockfile épingle le workflow réutilisable que tu appelles, mais les docs disent que ses propres dépendances sont couvertes par le lockfile du dépôt où il est défini, et recommandent d'intégrer d'abord les dépôts de workflows partagés. Je lis ça ainsi : un workflow partagé venant d'un autre dépôt n'est verrouillé que dans la mesure où ce dépôt l'est.
Dependabot garde les workflows intégrés synchronisés, en régénérant l'entrée du lockfile dans la même pull request que la montée de version. Il n'intégrera pas un workflow à ta place. Il « signale simplement que l'intégration est requise ».
La politique Require lockfile peut être testée en mode Evaluate, mais les docs disent que ce mode n'existe que sur GitHub Enterprise. Sur Free ou Team, la politique n'a pas de dry run.
Et c'est une préversion. Le README qualifie l'extension de pré-1.0 et prévient que le format du lockfile, les options des commandes et le comportement « peuvent changer sans préavis entre deux versions ». GitHub Enterprise Server n'est pas pris en charge. Le 19 octobre, les pages pratiques ne listaient encore que GitHub Enterprise Cloud sous « Who can use this feature? », alors que le changelog listait Team et Free dans une note de la rédaction, datée du 14 octobre, qui « a mis à jour les forfaits ayant accès ».
La limite que GitHub écrit lui-même
« Le verrouillage ne détermine pas si la dépendance elle-même est sûre, alors examinez les dépendances avant de les verrouiller. » Cette phrase est dans l'annonce, et c'est la plus importante. Si tu génères un lockfile pendant qu'un tag est empoisonné, tu as épinglé le malware, et chaque exécution suivante l'exécutera fidèlement.
Ce que le lockfile change, c'est le moment où tu l'apprends. Les branches et les versions partielles comme v3 ou main sont crues sur parole depuis le lockfile et ne sont pas résolues de nouveau lors d'une exécution normale. Si un tag en amont pointe maintenant ailleurs, l'extension s'arrête avec une erreur et c'est toi qui décides. gh actions-lock --relock accepte un déplacement légitime. Si le commit que tu avais verrouillé n'est plus du tout atteignable, « par exemple parce que le dépôt amont a été forcé en push ou supprimé », même --relock renvoie une erreur, et il te faut --accept-moved. C'est l'option que je ne laisserais jamais un script passer tout seul.
Le contrôle du commit imposteur a déjà été éprouvé en public. Le 15 octobre, François Proulx, de Boost Security, a signalé dans le suivi d'incidents de l'extension qu'une entrée de lockfile modifiée à la main, associée à un SHA complet qui n'existait que dans un fork de actions/checkout, avait passé gh actions-lock --verify et tourné sous le nom du dépôt amont dans un dépôt où Require lockfile était actif. Une exécution neuve de gh actions-lock rejetait le même commit. Le 16 octobre, un mainteneur a répondu que le défaut côté backend était corrigé, en ajoutant : « Je reviendrai sur la lacune dans la CLI la semaine prochaine. » Le 19 octobre, le ticket était toujours ouvert. Le rapport note que l'attaque exige qu'un contributeur fasse des modifications visibles à la fois dans le workflow et dans le lockfile.
Le guide d'application le dit sans détour : « Un lockfile n'est un contrôle de sécurité que si quelqu'un lit le diff. » Il suggère aussi une skill Copilot qui régénère le lockfile chaque fois que l'agent modifie un workflow, et la qualifie de « commodité plutôt que de contrôle ». J'orchestre mon travail avec Claude Code, et la même logique vaut pour tout agent de code : une consigne garde le fichier à jour, elle ne le relit pas.
Ce que je ferais en premier
- Active Dependabot pour GitHub Actions avant de créer le lockfile, comme le recommandent les docs.
- Liste chaque ligne
uses:, vérifie que chacune pointe vers une version prise en charge et récente, et regarde l'historique récent des tags de chaque action tierce que tu t'apprêtes à verrouiller. - Installe l'extension avec
gh extension install github/gh-actions-locket intègre un workflow en lui passant son chemin. Je commencerais par celui qui détient les secrets de déploiement ou de signature. - Relis le diff complet et la liste d'autorisation, puis committe.
- Ajoute un job qui lance
gh actions-lock --verifysur les pull requests et fais-en un contrôle obligatoire. Il attrape un lockfile périmé ; le rapport du 15 octobre montre qu'il ne remplace pas la lecture d'une entrée modifiée à la main. En local,gh actions-lock --verify-local --no-fixtourne hors ligne dans un hook de pre-commit, mais il vérifie seulement que chaque référence a une entrée, pas que les entrées sont dignes de confiance. - Mets
.github/workflows/actions.lockdans CODEOWNERS et exige l'approbation d'un code owner. - N'active Require lockfile qu'une fois chaque workflow visé intégré et quelque chose en place pour que ça le reste. Sache ce que ça t'achète : dans un autre ticket, un mainteneur a expliqué le 15 octobre pourquoi un lockfile cassé n'arrête pas les exécutions (échouer en mode fermé toucherait des workflows jamais intégrés) et a dit que la politique Require lockfile « est ce qui te donne le comportement fail closed ».
Cela s'inscrit dans une direction que GitHub a déjà prise : le 10 septembre, il a rendu cache-mode disponible pour tous sur tous les forfaits, un réglage de moindre privilège pour le cache d'Actions. Épingler ce qui s'exécute et limiter ce que ça peut toucher sont les deux moitiés du même travail.
Un tag est une promesse faite par le compte de quelqu'un d'autre. Un lockfile la transforme en un commit que tu as choisi. Bien choisir reste ton affaire.
Sources
- GitHub Changelog, "GitHub Actions workflow lockfiles in public preview" (14 octobre 2026)
- GitHub Docs, "Workflow dependency lockfiles" (consulté le 19 octobre 2026)
- GitHub Docs, "Locking action dependencies in a repository's workflows" (consulté le 19 octobre 2026)
- GitHub Docs, "Enforcing lockfiles for action dependencies" (consulté le 19 octobre 2026)
- GitHub, "gh-actions-lock" (README) (consulté le 19 octobre 2026)
- gh-actions-lock, ticket n° 174, "Full-SHA lock entries can accept a fork-only commit under the upstream action name" (ouvert le 15 octobre 2026, réponse d'un mainteneur le 16 octobre, consulté le 19 octobre 2026)
- gh-actions-lock, ticket n° 125, "A broken action.lock file causes it to be ignored" (réponse d'un mainteneur le 15 octobre 2026)
- The GitHub Blog, "What's coming to our GitHub Actions 2026 security roadmap" (26 mars 2026)
- GitHub Community, "Help Shape Workflow Dependency Locking" (1er mai 2026)
- GitHub Advisory Database, "tj-actions changed-files through 45.0.7 allows remote attackers to discover secrets by reading actions logs" (consulté le 19 octobre 2026)
- Aqua Security, "Update: Ongoing Investigation and Continued Remediation" (récit de l'incident Trivy) (publié le 22 mars 2026, mis à jour le 1er avril 2026)
- Snyk, "Trivy GitHub Actions Supply Chain Compromise" (20 mars 2026)
- GitHub Changelog, "Control GitHub Actions cache access with cache-mode" (10 septembre 2026)
