Blog / Guides pratiques

GhostAction : supprimer un secret ne le révoque pas

GhostAction exhume d’anciens secrets. Distinguez la rotation du nettoyage de l’historique Git, puis vérifiez que les identifiants exposés et la voie d’injection dans les workflows sont bien fermés.

Études doctorales en sécurité de l’information achevéesSoutenance universitaire réussie · Soutenance finale de thèse à venir

Le fichier est propre. Que dit l’émetteur de l’identifiant ?

Vous avez supprimé le secret. Avez-vous révoqué son accès ? GhostAction rend cette question pressante : un compte de mainteneur compromis peut introduire un workflow qui fouille les anciens commits autant que les fichiers actuels. Un arbre de travail propre ne vous dit pas si l’identifiant qu’il trouve fonctionne encore. Cette décision appartient au service qui l’a émis.

La campagne d’octobre 2026 est le point de départ, mais le livrable utile est une manière de clore l’incident preuves à l’appui. Je distingue trois questions : où subsiste du matériel secret, si l’émetteur l’accepte encore, et si l’attaquant peut introduire un autre workflow. Cette analyse s’appuie sur des recherches publiques et sur la documentation de GitHub ; aucun payload de la campagne n’a été exécuté ici. [1][2]

L’historique Git devient une entrée pour le runner compromis

StepSecurity décrit un security-audit.yml malveillant poussé directement sous l’identité d’un mainteneur compromis. Son checkout demande l’historique complet. Le script utilise ensuite git log -p --all pour examiner les patchs. Il tente aussi de récupérer les valeurs des secrets Actions configurés en injectant les noms découverts dans les workflows existants. Les noms indiquent quoi demander ; les valeurs sont ce que veut l’attaquant. [1]

Prenez l’historique d’illustration ci-dessous. Le commit B retire le jeton du fichier le plus récent, tandis que le commit A le contient toujours. Une recherche qui parcourt l’historique peut donc retrouver l’ancien texte. La collecte de l’attaquant reste toutefois limitée par les références récupérées, les motifs qui correspondent et les limites de sortie du payload. Ne transformez pas cette capacité en affirmation selon laquelle tous les secrets historiques ont été extraits.

Illustrative repository history; no real credential

A: config.env contains API_TOKEN=DEMO_NOT_A_REAL_TOKEN
B: config.env no longer contains API_TOKEN

Current file: absent
Earlier commit: present
Issuer status: a separate question

Un secret récupéré peut-il encore authentifier ?

Être récupérable et être valide sont deux propriétés indépendantes. Un ancien jeton peut rester visible après sa révocation sans plus donner accès à rien. Un jeton peut aussi disparaître du dépôt que vous contrôlez tout en restant utilisable depuis la copie de quelqu’un d’autre. GitHub recommande de révoquer ou de renouveler d’abord les identifiants exposés ; la réécriture de l’historique traite les copies restantes et exige une coordination avec les clones, les forks et les références. [2]

Cette distinction change ma lecture des statistiques de nettoyage. Le nombre de dépôts contenant d’anciens secrets en clair mesure un résidu public, pas le nombre d’identifiants qu’un émetteur accepterait encore. Elle change aussi le critère de validation : remplacer une variable de CI ne suffit pas si l’ancien identifiant n’est pas désactivé chez son émetteur. Consignez-le séparément du fait que les builds fonctionnent avec le nouveau.

                              Old credential accepted?
                              Yes                 No
Secret text recoverable       Access remains       Residual disclosure
Secret text no longer found   Access may remain    Both checks needed

A repository scan cannot answer the issuer-status column.

Quel contrôle arrête vraiment le prochain workflow ?

Les exigences de relecture n’aident que là où elles sont appliquées. Le contrôle d’approbation de GitHub pour les workflows issus de forks publics concerne cette voie de contribution ; ce n’est pas une barrière d’approbation universelle pour le push direct d’un mainteneur. StepSecurity rapporte qu’une barrière d’approbation a stoppé certaines exécutions observées, mais cette observation ne prouve pas que le réglage relatif aux forks protège chaque dépôt contre cette campagne. [1][3]

Sur une branche protégée, exigez des pull requests et la relecture du code owner concerné, puis examinez qui peut contourner la règle. Une entrée CODEOWNERS pour .github/workflows/ définit la responsabilité ; la règle de branche rend cette relecture obligatoire. Protégez aussi le fichier CODEOWNERS lui-même, et examinez les autres branches dont les workflows de push peuvent recevoir des secrets. Protéger main seule ne couvre pas tous les chemins d’exécution des workflows. [4][5]

Un jeton de dépôt en lecture seule peut accompagner un vol de secrets

Réduire les permissions de GITHUB_TOKEN est utile, mais cela ne révoque pas un identifiant cloud transmis séparément à un job. Le workflow observé pouvait fonctionner avec le contenu du dépôt en lecture seule tout en collectant d’autres identifiants. Une revue des permissions doit donc inventorier à la fois le jeton intégré et chaque secret distinct mis à disposition de l’exécution. [1]

Ma revue suit une chaîne concrète : qui peut modifier le workflow, quel événement le déclenche, quelle identité et quels secrets le job reçoit, et quelles destinations il peut contacter. Pour un job de publication, la question est de savoir si l’auteur d’un workflow peut transformer ce job en lecteur d’identifiants. Restreindre l’écriture dans le dépôt ne répond qu’à une partie de cette chaîne. C’est une question de revue d’architecture, pas l’affirmation que chaque runner a exposé tous les secrets.

Contenir l’accès avant de peaufiner l’historique du dépôt

Conservez la révision du workflow, les identifiants des exécutions et les journaux d’audit pertinents avant que le nettoyage n’efface le contexte. Coupez la voie d’exécution malveillante et révoquez l’identifiant du mainteneur compromis. Inventoriez ensuite les secrets actuels des jobs et les identifiants historiques compris dans le périmètre d’exposition, attribuez chacun à un responsable et faites constater la révocation auprès du service émetteur. Lorsque la validité ne peut pas être établie, traitez le point comme non résolu plutôt que de déclarer le dépôt propre. [1][2]

Un identifiant de remplacement doit passer par une voie d’exécution de confiance. Sinon, le même workflow compromis peut le lire à l’exécution suivante. Le nettoyage de l’historique s’accompagne de son propre travail de coordination et ne peut pas rappeler les copies déjà obtenues par un attaquant. Pour les clés capables de créer des sessions ou d’autres identifiants, examinez aussi cet accès en aval ; désactiver le secret d’origine ne prouve pas logiquement qu’aucun accès distinct n’a été établi.

Demandez un dossier de clôture, pas une capture d’écran propre

Un dossier de remédiation doit permettre à un autre ingénieur de distinguer le travail accompli des suppositions. Pour chaque identifiant exposé, conservez son identifiant non secret, son responsable, le système émetteur, la fenêtre d’exposition, la preuve de révocation et l’état du déploiement du remplacement. Consignez comment l’identité utilisée pour l’injection a été contenue et comment la voie des workflows a été restreinte. La grille ci-dessous est un support de revue proposé, pas la transcription de cet incident.

La question de l’acheteur devient précise : votre équipe peut-elle montrer que l’accès précédemment exposé n’est plus accepté et que le remplacement ne peut pas fuiter par la même voie ? C’est la preuve que je demanderais lors d’une vérification de la remédiation. Elle fait la différence entre clore un ticket et clore l’accès qu’il devait supprimer.

Credential ID / owner / issuer: ____________________
Exposure scope and evidence: _______________________
Old credential disabled at issuer: _________________
Replacement deployed through trusted workflow: _____
Compromised maintainer access contained: ____________
Other credentials or sessions investigated: _________
Remaining copies / uncertainty / responsible owner: _

Sources

Besoin de vérifier ce point dans votre propre produit ?

Remédiation et vérification des correctifs

Vous voulez apprendre à trouver vous-même ce type de vulnérabilité ?

Formation individuelle à la revue de code sécurisé
Tous les articles

08Contact

Vous livrez un produit qui traite des données d’utilisateurs ?

Envoyez-moi un bref descriptif. Je réponds sous trois jours avec des questions ou une première proposition, et le prix est fixé par écrit avant le démarrage.