Retour
17 mars 2025
Attaque de la chaîne d'approvisionnement GitHub Actions : Que s'est-il passé et comment l'avons-nous détectée

Frank Lyonnet

Introduction
Une attaque critique de chaîne d'approvisionnement – une attaque ciblant un composant largement utilisé dans le pipeline de développement – a frappé la communauté GitHub Actions le 14 mars 2025. Une action GitHub populaire (composant de workflow CI/CD réutilisable) appelée tj-actions/changed-files a été compromise, mettant en danger des milliers de pipelines d'intégration continue. Dans cette attaque, le code de l'action a été modifié pour divulguer des secrets (comme des clés API et des tokens) provenant des pipelines CI/CD en les imprimant dans les journaux de construction. Étant donné que beaucoup de ces pipelines sont publics, les secrets sensibles ont été exposés à quiconque, ce qui pourrait conduire à un accès non autorisé s'ils étaient utilisés de manière malveillante.
Heureusement, l'incident a été rapidement détecté en temps réel par l'outil Harden-Runner de StepSecurity, qui a signalé un appel réseau inhabituel lors d'une exécution de workflow. La communauté de la sécurité et GitHub ont réagi rapidement : le code malveillant a été identifié et neutralisé, et une entrée CVE officielle (Vulnérabilités et Expositions Courantes) (CVE-2025-30066) a été émise pour suivre cet incident. Cet article décompose ce qui s'est passé en termes simples, comment il a été détecté et reproduit par EDAMAME, et ce que les équipes DevSecOps peuvent apprendre pour mieux sécuriser leurs pipelines CI/CD.
Résumé de l'incident
L'action tj-actions/changed-files est utilisée dans plus de 23 000 dépôts, aidant à automatiser la détection des fichiers modifiés dans les workflows GitHub. Le 14 mars 2025, des attaquants ont obtenu un accès non autorisé au dépôt de cette action et ont mis à jour rétroactivement de nombreux tags de version pour pointer vers un seul commit malveillant. En termes simples, même les versions plus anciennes de l'action ont été soudainement redirigées pour exécuter du code fourni par les attaquants. Le code compromis incluait une charge utile cachée encodée en base64 (un morceau de données encodées pour dissimuler son véritable objectif). Lorsque le pipeline CI exécutait l'action changed-files, cette charge utile serait décodée en un script Python récupéré depuis une URL externe sur gist.githubusercontent.com. Ce script cherchait dans la mémoire de l'exécuteur des secrets CI/CD (mots de passe, clés, tokens définis comme secrets d'environnement) et imprimait ensuite ces secrets dans la sortie des journaux du job.
Étant donné que de nombreux projets utilisant cette action sont open source, leurs journaux de workflow sont souvent publics. Cela signifiait que tous les secrets divulgués par le script malveillant étaient visibles pour quiconque lisait les journaux. L'impact a été sévère : des informations d'identification telles que des clés de cloud, des tokens GitHub, et d'autres ont été exposées. Notamment, les enquêteurs n'ont trouvé aucune preuve que les secrets volés aient été envoyés au serveur d'un attaquant – au lieu de cela, la menace était que les secrets étaient simplement là dans les journaux pour un accès opportuniste.
Comment a-t-il été attrapé ? Le Harden-Runner de StepSecurity – un agent de sécurité pour les exécuteurs GitHub Actions – a détecté l'attaque presque immédiatement. Harden-Runner surveille le comportement des workflows (par exemple, surveillant les appels réseau, les modifications de fichiers et les processus) et a remarqué un point de terminaison externe inattendu dans le trafic réseau de l'action. Dans ce cas, le workflow a tenté de contacter gist.githubusercontent.com
(où le script malveillant était hébergé), ce qui n'était pas un point de terminaison normalement observé dans ce contexte. Cette anomalie a déclenché une alerte. En essence, Harden-Runner a agi comme une caméra de sécurité sur l'exécuteur CI : dès que l'action a essayé de faire quelque chose d'inhabituel (accéder à une URL externe qui n figurait pas sur une liste autorisée), cela a été signalé. Cette détection précoce a permis à l'équipe d'enquêter avant que des dommages supplémentaires ne soient causés.
La communauté plus large de la sécurité a rapidement collaboré pour diagnostiquer le problème. Des contributeurs comme sur GitHub ont fouillé le dépôt de l'action et ont localisé le commit malveillant exact qui avait été inséré. Ils ont découvert que tous les tags de version de v1.0.0 jusqu'à la plus récente pointaient vers un seul commit – la charge utile des attaquants. Cette manipulation rétroactive des tags est ce qui a rendu l'attaque un compromis de chaîne d'approvisionnement : tous ceux qui intégraient n'importe quelle version de l'action exécuteraient sans le savoir le code de l'attaquant. Le code malveillant, une fois décodé à partir de base64, montrait clairement la logique pour récupérer le script externe memdump.py
et déverser des secrets, confirmant le comportement suspecté.
GitHub a répondu en retirant l'action compromise de la plateforme pour empêcher d'autres usages. Dans la journée, le dépôt original a été temporairement désactivé puis restauré à un état sûr (avec les tags malveillants retirés) une fois le problème résolu. Un avis officiel a été publié, et la CVE a été enregistrée pour s'assurer que l'incident soit suivi et que les utilisateurs puissent consulter les détails sur ce problème de sécurité.
Implications pour la sécurité CI/CD
Cette attaque a des implications stark pour la sécurité des pipelines CI/CD et illustre pourquoi les attaques de chaîne d'approvisionnement sur les outils de développement sont si dangereuses :
Impact généralisé d'un seul compromis : Parce que
tj-actions/changed-files
était largement utilisé, un seul point de compromis a eu des répercussions sur des milliers de projets en aval héritant du code malveillant. Les pipelines CI/CD réutilisent souvent des actions et des dépendances partagées ; si l'une d'entre elles est compromise, cela peut affecter chaque projet qui l'utilise. Dans ce cas, tout dépôt exécutant l'action empoisonnée a commencé à déverser automatiquement ses secrets. C'est un rappel saisissant que nos systèmes CI/CD ne sont sécurisés que par le maillon le plus faible de notre chaîne d'approvisionnement.Pourquoi cette attaque était-elle possible ? L'attaque a été possible en raison d'une combinaison de facteurs : confiance implicite dans les actions tierces, accès large au sein de l'environnement CI, et non-vérification suffisante. Les mainteneurs de l'action avaient un compte de bot avec un PAT qui a été compromis – une fois que l'attaquant a eu accès en écriture, il pouvait introduire du code malveillant. De nombreux projets référencent les actions GitHub par tag (par exemple,
uses: tj-actions/changed-files@v35
), supposant que ce tag pointe vers du code sûr. L'attaquant a abusé de cela en réétiquetant les versions vers le commit malveillant, de sorte que même les numéros de version fixés n'étaient pas sûrs. De plus, l'environnement GitHub Actions a permis au code malveillant de réaliser des opérations hautement sensibles : il a pu exécutersudo
et lire la mémoire d'un autre processus pour attraper des secrets, ce qui indique un manque de moindre privilège dans la configuration par défaut de l'exécuteur. Essentiellement, l'exécuteur CI était un environnement entièrement privilégié avec accès à Internet – parfait pour abus si un acteur malveillant peut exécuter du code à l'intérieur.Risques d'utilisation des actions GitHub publiques : Cet incident met en lumière le risque de chaîne d'approvisionnement lié à la consommation des Actions communautaires. Lorsque vous utilisez une action GitHub publique dans votre workflow, vous exécutez le code de quelqu'un d'autre avec vos privilèges. Ce code peut avoir accès à votre dépôt, vos informations d'identification cloud, et d'autres secrets. Si l'action est ensuite altérée (comme cela s'est produit ici), votre pipeline exécutera aveuglément les mises à jour malveillantes. Dans ce cas, l'action malveillante a exposé des secrets CI (qui peuvent inclure des clés de fournisseur de cloud, des clés de signature, etc.), ce qui pourrait mener à de nouveaux compromis de l'infrastructure. Même si les secrets du dépôt sont masqués dans les journaux, le tour de double-encodage de l'attaquant a vaincu le masquage des secrets de GitHub, démontrant que compter uniquement sur le masquage automatique est insuffisant. De plus, une action avec une intention malveillante pourrait faire plus que simplement divulguer des secrets : elle pourrait altérer des artefacts, injecter des portes dérobées dans du code construit, ou modifier la logique de déploiement. L'utilisation d'actions tierces introduit donc une dépendance en confiance significative. Malheureusement, la conception même des CI/CD (automatisation rapide, extensible, basée sur des plugins) signifie que ces dépendances sont courantes – c'est pourquoi les attaquants ciblent de plus en plus ces systèmes.
Défis pour prévenir des attaques similaires : Prévenir ce type d'attaque est difficile. Les contrôles de sécurité traditionnels (comme la révision de code ou le scan) échouent souvent : le changement malveillant ici était obfusqué (script encodé en base64) et introduit dans un projet de confiance, donc il pourrait ne pas déclencher d'alerte rouge jusqu'à ce qu'il soit en cours d'exécution. Les propres mécanismes de GitHub ont finalement identifié et supprimé l'action compromise, mais seulement après qu'elle ait été active pendant un certain temps. La nature éphémère des exécutants CI et la rapidité des déploiements signifient que le code malveillant peut s'exécuter et disparaître avant que quiconque ne s'en aperçoive. De plus, de nombreuses organisations manquent de surveillance sécurité sur les systèmes CI – contrairement aux serveurs de production, les exécutants CI n'ont généralement pas de protection ni de surveillance par défaut. Ce "point aveugle" a conduit à de multiples attaques de chaîne d'approvisionnement logicielle ces dernières années. Un autre défi est que les pratiques de commit ou de pinning de version dans le CI ne sont pas toujours strictes. Comme noté, si les projets avaient fixé l'action à un commit SHA spécifique, ils auraient été immunisés contre la réétiquetage des tags. Mais épingler chaque action à un commit est souvent négligé pour des raisons de commodité, et même avec le pinning, il faudrait mettre à jour le pin pour obtenir des correctifs de sécurité – ce qui constitue un défi de gestion. En résumé, la nature dynamique et interconnectée de CI/CD rend difficile la prévention complète de ces attaques de chaîne d'approvisionnement ; au lieu de cela, les organisations doivent supposer qu'un compromis est possible et mettre en place des mesures de détection et d'atténuation (défense en profondeur).
Comment la menace a été détectée
Il est important de comprendre comment cette attaque a été interceptée, car cela met en évidence une pratique clé pour défendre les pipelines CI/CD. La surveillance de l'egress réseau (connexions réseau sortantes) – comme la connexion à un domaine inhabituel ou un processus essayant d'exporter des données – était le mécanisme clé capable de détecter la menace.
Les exécutants hébergés par GitHub sont éphémères (à courte durée de vie) et souvent non surveillés par des outils de sécurité d'entreprise. Dans cet incident, la connexion à un domaine inattendu était le drapeau rouge. Puisque le workflow ne devrait pas contacter gist.githubusercontent.com
(une adresse qui ne figure pas sur la liste normale des domaines autorisés pour cette action), l'activité a été immédiatement signalée. Cela a donné aux équipes de sécurité un avertissement pour agir rapidement.
Reproduire et détecter l'attaque avec EDAMAME Posture
L'équipe de sécurité EDAMAME a reproduit l'attaque dans un environnement contrôlé. EDAMAME se spécialise dans la vérification de la posture de sécurité (état de sécurité global) des appareils et des environnements en utilisant des listes d'autorisation strictes (whitelists) de ce qui est autorisé. Dans notre test, nous avons exécuté un workflow GitHub Actions contenant la version malveillante de l'action changed-files pour observer son comportement. Comme prévu, l'action a effectué un appel réseau non autorisé afin d'obtenir une charge utile destinée à déverser des secrets – imitant le scénario de l'attaque réelle.
Cependant, grâce aux contrôles de Posture d'EDAMAME, notre équipe avait des listes blanches prédéfinies qui n'autorisent que les activités et connexions approuvées lors d'un exécution CI. Pensez à cela comme à une approche de confiance zéro : même au sein du job CI, seuls des processus et destinations réseau connus et fiables sont autorisés. Lorsque l'action malveillante a essayé d'exécuter le script memdump.py
et d'envoyer les secrets, la politique d'EDAMAME l'a détecté parce qu'il n'était pas sur la liste des comportements approuvés.
Le résultat du test de reproduction a montré que l'attaque a été détectée avec succès. Cela démontre la puissance d'une stratégie de liste d'autorisation (whitelist) : même si un acteur malveillant glisse du code malveillant dans votre pipeline, des outils comme EDAMAME peuvent garantir que seules les connexions pré-autorisées (par exemple, se connecter à des serveurs de build connus ou des API internes) sont autorisées, et rien de plus.
L'importance du durcissement des systèmes et de la visibilité réseau approfondie
L'approche d'EDAMAME pour la sécurité CI/CD se concentre à la fois sur le durcissement des systèmes et sur une visibilité réseau approfondie. Au lieu de simplement instrumenter au niveau de l'application, la solution d'EDAMAME (EDAMAME Posture) effectue un contrôle de posture au niveau du système d'exploitation, puis engage un mécanisme de capture de paquets pour surveiller tout le trafic réseau de l'exécutant CI. Elle fonctionne sur plusieurs plateformes – prenant en charge les exécutants sous Windows, macOS et Linux – en utilisant des pilotes de capture de paquets à bas niveau appropriés (npcap sur Windows, et pcap sur Linux et macOS). Une fois intégrée dans un workflow (comme étape de configuration), EDAMAME Posture enregistre chaque requête réseau sortante que le job effectue. Cela inclut non seulement les appels HTTP/HTTPS, mais aussi tout le trafic TCP/UDP, les requêtes DNS, etc. Le trafic capturé est ensuite analysé (en utilisant des outils comme Zeek pour l'analyse réseau) pour détecter des motifs suspects. Par exemple, EDAMAME peut détecter si une étape de pipeline essaie d'effectuer un tunneling DNS ou de contacter une IP qui ne figure pas sur une liste de confiance, car il a une visibilité totale au niveau des paquets sur les communications de l'exécutant. De plus, l'agent d'EDAMAME effectue un "contrôle de posture" sur le système de l'exécutant au début de chaque exécution de workflow, garantissant que les paramètres du système d'exploitation sont durcis, que les mises à jour requises sont en place, qu'aucun service inattendu ou ports ouverts ne sont présents et que la segmentation réseau est en place. Cela réduit la surface d'attaque avant que la construction ne s'exécute.
Dans le contexte de l'attaque changed-files, l'approche de capture de paquets d'EDAMAME aurait également capté l'appel sortant vers le Gist de GitHub – même si le malware avait utilisé un protocole non-HTTP ou une forme d'obfuscation, cela apparaîtrait toujours dans le journal des paquets. En enregistrant tout le trafic sortant, EDAMAME crée une piste d'audit complète de l'activité réseau, ce qui est inestimable lors de la réponse à un incident (vous pouvez rétroactivement voir exactement quelles connexions ont été effectuées). L'utilisation de Zeek (un puissant moniteur de sécurité réseau) signifie qu'il peut également détecter des techniques d'exfiltration subtiles – par exemple, repérer si des données secrètes ont été encodées dans des requêtes DNS ou si de grandes quantités de données étaient envoyées à un hôte inhabituel.
La méthode d'EDAMAME fournit une visibilité réseau approfondie et un support multi-OS, complétant d'autres outils avec un verrouillage système complet. Elle introduit efficacement une philosophie de confiance zéro dans le pipeline CI : supposez que chaque étape de construction pourrait être malveillante et vérifiez/surveillez tout. En capturant des paquets et en vérifiant en continu la posture du système, EDAMAME vise à détecter ce que d'autres pourraient manquer et à limiter les dommages que le code malveillant peut causer.
Mesures de récupération
Cet incident, bien que sérieux, fournit des leçons précieuses. Si vous utilisiez l'action compromise ou souhaitez simplement renforcer vos défenses, envisagez les mesures de récupération et les meilleures pratiques suivantes :
Arrêtez d'utiliser le composant infecté (plus nécessaire maintenant que le dépôt a été corrigé) : Si l'un de vos workflows utilise tj-actions/changed-files, désactivez ces exécutions de workflow et remplacez cette action immédiatement. Assurez-vous toujours d'utiliser une version des actions tierces en lesquelles vous avez confiance. En général, privilégiez les actions qui sont bien entretenues ou qui ont fait l'objet d'une révision de sécurité.
Fixez les dépendances à des versions immuables : Une des raisons pour lesquelles cette attaque a été efficace est qu'elle a exploité des tags de version mutables (comme des tags
vX.Y.Z
qui ont été modifiés malicieusement). Une meilleure pratique pour contrer cela est de fixer vos actions GitHub à un commit SHA spécifique ou à une version étiquetée que vous contrôlez. En épinglant à un hash de commit, vous vous assurez que même si un tag est déplacé ou qu'une nouvelle version est publiée, votre workflow n'exécutera pas automatiquement du code non fiable. C'est un peu comme geler une dépendance logicielle à une version connue et sûre.Auditez vos workflows pour les actions affectées : Recherchez dans votre codebase toutes les références à
tj-actions/changed-files
. Cela peut être fait via la recherche de GitHub ou d'autres outils de recherche de code. Assurez-vous d'identifier chaque endroit où il a été utilisé, y compris les anciennes branches ou modèles, et mettez à jour ou supprimez ces références.Examinez les journaux CI/CD pour des secrets divulgués : Si vous avez utilisé l'action compromise, vérifiez vos journaux d'exécution GitHub Actions récents pour toute sortie suspecte. En particulier, recherchez des chaînes en base64 longues ou toute ligne où des secrets (comme
AWS_ACCESS_KEY=
ou d'autres tokens) apparaissent en texte clair. Le code malveillant imprimerait des secrets dans un format ressemblant à JSON. Repérer ces éléments dans vos journaux signifie que ces secrets ont été exposés. Pour les dépôts publics, supposez que tout ce qui se trouve dans les journaux a été vu et copié par quelqu'un d'autre à ce stade.Faites tourner immédiatement les secrets exposés : Pour tout secret qui a été affiché dans les journaux (ou pour toute information d'identification que vous soupçonnez d'avoir été compromise), effectuez leur rotation. Cela signifie générer de nouvelles clés, mots de passe ou tokens pour remplacer les anciens. Par exemple, si une clé AWS a fui, allez sur votre console AWS pour désactiver cette clé et en créer une nouvelle. Il est crucial de faire cela rapidement – une fois tournés, les anciennes informations d'identification divulguées ne peuvent plus être utilisées par les attaquants.
Nettoyez les journaux de construction compromis : Si possible, supprimez ou rendez privés tous les journaux CI/CD qui contenaient des secrets. Cela ne permettra pas d'annuler la fuite (les attaquants peuvent déjà les avoir), mais cela empêche l'accès occasionnel ou l'indexation par les moteurs de recherche de ces secrets. Retirer les preuves de la vue publique est une étape d'hygiène de base après avoir tourné les secrets.
Implémentez une sécurité en temps d'exécution pour CI/CD : Cette attaque souligne que nous ne pouvons pas faire confiance aveuglément à chaque action ou dépendance de nos pipelines. Introduisez des outils de sécurité dans vos workflows pour ajouter une surveillance en temps réel. Ces solutions vont vous alerter sur des comportements inhabituels (et même les bloquer) lorsqu'ils se produisent. Cela est particulièrement important pour détecter des choses comme une étape de construction faisant soudainement un appel réseau à un serveur inconnu ou un processus essayant d'accéder à des fichiers sensibles.
Utilisez des listes d'autorisation pour le réseau et les appareils : Renforcez votre pipeline avec une mentalité de confiance zéro. L'utilisation d'EDAMAME ou d'outils similaires de gestion de posture peut garantir que même si un secret est volé, il ne peut pas être utilisé à partir d'une machine ou d'un emplacement non reconnu. Par exemple, vous pouvez restreindre certains clés de déploiement pour qu'elles fonctionnent uniquement depuis le réseau de votre entreprise ou depuis vos exécutants CI officiels. En whitelistant les appareils et points de terminaison approuvés, vous ajoutez un filet de sécurité : un attaquant s'emparant seul d'une chaîne secrète ne sera pas suffisant pour compromettre davantage vos systèmes.
Restez informé et appliquez les mises à jour : Restez à l'affût des flux de sécurité (comme les avis de sécurité GitHub ou les bulletins CVE) pour tout problème concernant les plugins/actions que votre équipe utilise. Si un problème critique touche quelque chose dans votre chaîne d'outils, traitez-le avec la même urgence que vous le feriez pour un incident de production. Dans ce cas, la communauté et GitHub ont agi rapidement – assurez-vous que votre équipe est à l'écoute pour pouvoir réagir rapidement également.
Pratiquez la réponse aux incidents pour CI/CD : Cet incident est un rappel d'avoir un plan de réponse spécifiquement pour votre pipeline de construction. Sachez à l'avance comment désactiver un composant compromis, comment révoquer des informations d'identification, et comment communiquer à votre équipe ou à vos utilisateurs concernant le problème. Plus vous pouvez le faire rapidement, moins les attaquants auront une fenêtre pour exploiter les informations divulguées.
En suivant les étapes ci-dessus, vous pouvez réduire significativement le risque de ce type d'attaque et améliorer votre posture de sécurité CI/CD globale.
Conclusion et Principales Remises en Question
La compromission de tj-actions/changed-files rappelle que les pipelines CI/CD font partie de notre chaîne d'approvisionnement logicielle et sont des cibles de grande valeur pour les attaquants. Dans ce cas, l'attaquant n'a pas visé le code source ou un système de production directement – il s'est attaqué à un outil tiers dans le processus de construction, sachant qu'il était largement utilisé. L'impact a été l'exposition de secrets, ce qui aurait pu mener à des violations supplémentaires (comme un accès non autorisé à des comptes cloud ou des registres de paquets) s'il n'avait pas été rapidement traité.
Cependant, cet incident met aussi en lumière comment les bonnes mesures de sécurité peuvent transformer une attaque potentiellement catastrophique en un risque géré. Une surveillance en temps réel par des outils peut offrir un avertissement précoce, et l'application stricte de la posture de sécurité par des solutions comme EDAMAME peut contenir le rayon d'explosion en cas de problème. Pour les équipes DevSecOps, cet événement offre un plan clair :
Investissez dans la sécurité CI/CD comme vous le feriez pour la sécurité de production. Cela inclut l'ajout de surveillance, l'utilisation des principes de moindre privilège pour les informations d'identification dans les pipelines, et la mise à jour et le pinning des dépendances.
Adoptez une approche de défense en profondeur. Aucun outil ou pratique unique n'est infaillible, mais plusieurs couches (révision de code des actions tierces, surveillance en temps réel, liste d'autorisation réseau, confiance dans les appareils, etc.) créent un bouclier robuste où si une couche échoue, d'autres attraperont le problème.
Rendez la sécurité conviviale pour les développeurs. Les solutions qui ont fonctionné ici l'ont fait avec un minimum de friction – un agent léger dans un workflow, un mécanisme automatique de liste blanche – ce qui signifie que les développeurs peuvent maintenir leur vélocité. Lorsque la sécurité est intégrée de manière transparente, elle est plus susceptible d'être adoptée et efficace.
Enfin, la leçon pratique est celle de la vigilance et de la préparation. Les attaques de chaîne d'approvisionnement peuvent être sournoises et sophistiquées, mais avec la collaboration de la communauté et les outils modernes de DevSecOps à notre disposition, nous pouvons détecter et atténuer ces menaces avant qu'elles ne wreak havoc. En sécurisant nos pipelines CI/CD maintenant, nous protégeons non seulement notre code, mais aussi les informations d'identification et l'infrastructure sur lesquelles ce code repose. À une époque où l'automatisation est reine, assurons-nous que notre automatisation est digne de confiance et résiliente contre les attaques.
Restez prudents, gardez vos pipelines durcis, et rappelez-vous que chaque lien dans la chaîne d'approvisionnement compte – du code à la construction jusqu'au déploiement. Avec les leçons tirées d'incidents comme celui-ci, nous pouvons tous renforcer nos défenses et continuer à livrer des logiciels rapidement et en toute sécurité.
Frank Lyonnet
Partagez ce post