Skip to content

Cet outil n'est ni affilié à GitHub, Inc. ou à Microsoft Corporation, ni approuvé ou sponsorisé par elles. GitHub et GitHub Actions sont des marques de GitHub, Inc. Les autres noms sont des marques de leurs propriétaires respectifs.

Enquête sur une attaque supply chain GitHub : cas pratique

Attaque supply chain GitHub fictive analysée de bout en bout : PAT volé, 38 dépôts clonés, clés AWS affichées par un workflow, protection de branche retirée.

Publié le 7 min de lecture

En bref. Ce cas pratique s'appuie sur l'incident fictif du bouton « Essayer un exemple » de l'outil (organisation northwind-labs ; personnes, dépôts, jetons et adresses IP sont tous inventés). Le jeton d'accès personnel (PAT) classique d'un développeur est rejoué depuis un VPS aux Pays-Bas à 01:58 UTC. Il clone 38 dépôts privés en 18 minutes environ, pousse sur une nouvelle branche un workflow qui affiche les clés de déploiement AWS encodées deux fois en base64, ajoute une clé de déploiement en écriture et supprime la protection de branche sur main. L'analyseur rend le verdict Compromis avec 10 constats. Voici comment les lire et dans quel ordre agir.

Scénario fictif. Tout le contenu de cet article provient de scripts/make-samples.py, qui génère l'exemple servi par le bouton « Essayer un exemple » de l'outil. Les adresses IP proviennent des plages réservées à la documentation (RFC 5737), et la paire de clés AWS est l'exemple officiel de la documentation AWS. Toute ressemblance avec une organisation réelle serait fortuite.

Le contexte

northwind-labs est une petite organisation d'ingénierie : une propriétaire (c-okafor) et trois développeurs (m-hernandez, j-lindqvist, a-nowak) qui travaillent surtout depuis la France et la Suède, aux heures de bureau. Les preuves sont les trois fichiers qu'un enquêteur collecterait réellement, chacun dans son format d'export réel :

FichierSourceContenu
northwind-labs-audit-log.jsonJournal d'audit de l'organisation, export JSON depuis l'interfaceModifications des membres, exécutions de workflows, secrets, clés, protection de branche
export-northwind-labs-1789360000.json.gzExport des événements Gitgit.clone / git.fetch / git.push avec les métadonnées des jetons
northwind-labs-actions-run-4412.zip« Download log archive » d'une exécutionLogs des étapes de l'exécution de workflow suspecte

La base de référence couvre trois semaines (du 2026-08-24 au 2026-09-13). C'est important, car les règles « nouveau pays » et « nouvelle adresse IP » ont besoin d'un historique pour comparer.

Étape 1 : le verdict

Déposez les trois fichiers (ou cliquez sur Essayer un exemple). Le bandeau indique Compromis. Sous Pourquoi, quatre constats l'ont déterminé : actions-secret-exfil (critique), ainsi que token-new-country, git-clone-burst et branch-protection-removed (élevée). Les notes de couverture sont vides. Adresses IP, événements Git et métadonnées des jetons sont tous présents : aucune règle n'était aveugle.

La liste complète, telle que l'analyseur la présente :

GravitéRègleQuand (UTC, le 2026-09-14 sauf mention contraire)Quoi
critiqueactions-secret-exfil02:40:08Le script de l'étape fait passer les clés AWS deux fois dans base64. Rebond suivant : AWS
élevéetoken-new-country01:58:12 → 03:06:3043 événements depuis les Pays-Bas pour un jeton jamais vu ailleurs qu'en France
élevéegit-clone-burst02:14:00 → 02:31:5338 dépôts distincts clonés depuis 203.0.113.66
élevéebranch-protection-removed03:05:44main sur payments-api
moyenneactions-encoded-output02:40:08Longue chaîne base64 affichée dans la même étape
moyennedeploy-key-added02:52:03Clé backup-sync sur infra-terraform, accès en écriture
faibletoken-new-ip01:58:12 → 03:06:30Les mêmes 43 événements, nouvelle adresse IP
faibleworkflow-new-branch02:39:40Le workflow CI s'exécute pour la première fois sur ci/cache-fix
faibleactions-secret-created2026-09-08a-nowak a créé les secrets AWS, légitime
faiblewebhook-created2026-09-03a-nowak a créé un webhook de CI, légitime

Les deux derniers constituent le bruit normal de toute organisation réelle : des tâches d'administration courantes que les règles font remonter parce qu'elles pourraient compter. Ils ne partagent ni acteur, ni jeton, ni adresse IP avec le reste : vous pouvez les écarter.

Étape 2 : quel identifiant ?

Ouvrez token-new-country. Ses entités sont l'acteur m-hernandez, un hashed_token et l'adresse IP 203.0.113.66. Pivotez sur le jeton (Entités → Tokens → Voir les événements). Il s'agit d'un Personal access token (classic) avec les scopes repo, workflow, read:org. Pendant trois semaines, il a été utilisé depuis 198.51.100.23 (France) avec le user agent git/2.39.5 (Apple Git-154), en journée. À partir de 01:58 UTC le 2026-09-14, il apparaît depuis 203.0.113.66 (Pays-Bas) avec git/2.43.0, puis avec curl/8.5.0.

Même personne, même jeton, autre machine, autre pays, en pleine nuit : le jeton a été rejoué. Le scope workflow explique comment l'attaquant a pu pousser un fichier de workflow. Dans le scénario, la source est un infostealer sur le poste du développeur. Les logs GitHub ne peuvent pas montrer cette partie, c'est pourquoi le playbook sur les jetons fuités insiste sur la vérification du poste.

Étape 3 : qu'a-t-il emporté ?

git-clone-burst compte 38 dépôts distincts. Dans les événements Git, les clonages s'étalent de 02:14:00 à 02:31:53, soit un toutes les 29 secondes environ. Un rythme aussi régulier trahit un script. m-hernandez travaille normalement sur quatre dépôts (payments-api, billing-worker, ledger, web-app). La rafale inclut infra-terraform, secrets-rotation, kyc-service et terraform-modules, des dépôts sur lesquels il n'a jamais poussé.

Conclusion pour le rapport : le code source et l'historique complet de 38 dépôts sont entre les mains de l'attaquant. L'action de remédiation « Considérez le code cloné comme divulgué » en découle : analysez ces historiques à la recherche de secrets et renouvelez ceux que vous trouvez. L'article sur l'exfiltration de dépôts explique comment délimiter ce périmètre.

Étape 4 : qu'a-t-il modifié ?

Lisez la chronologie avec Constats uniquement :

  1. 02:39:21 git.push vers payments-api depuis le VPS.
  2. 02:39:40 workflows.created_workflow_run : workflow CI, événement push, branche ci/cache-fix. C'est la première exécution sur cette branche, donc workflow-new-branch se déclenche.
  3. 02:40:08 Dans l'archive de logs de l'exécution 4412, l'étape Restore build cache exécute echo "$AWS_ACCESS_KEY_ID:$AWS_SECRET_ACCESS_KEY" | base64 -w0 | base64 -w0 et affiche une longue chaîne. Le masquage ne s'est pas appliqué, car la valeur était encodée. Décodée deux fois, elle donne la paire de clés (ici, l'exemple de la documentation AWS). actions-secret-exfil se déclenche en critique avec le rebond suivant AWS, et actions-encoded-output se déclenche sur la chaîne.
  4. 02:52:03 public_key.create sur infra-terraform : titre backup-sync, read_only: false, user agent curl/8.5.0. Une clé de déploiement en écriture est une persistance qui survit à la révocation du PAT.
  5. 03:05:44 protected_branch.destroy sur payments-api / main. La règle exigeait deux reviews approbatrices.
  6. 03:06:30 git.push vers payments-api, une minute après la levée de la protection.
  7. 07:48:10 protected_branch.create par c-okafor depuis le bureau : la propriétaire s'en est aperçue et a rétabli la règle.

L'étape 6 est celle qui doit le plus vous inquiéter. Quelque chose a été poussé sur main sans review. Le journal d'audit ne contient pas le diff : le commit doit donc être examiné dans le dépôt (voir altération de la protection de branche).

Étape 5 : la remédiation, dans l'ordre de l'outil

L'onglet Remédiation classe la checklist par urgence :

  1. Préservez les preuves : réexportez le journal d'audit et les événements Git, et conservez l'archive de logs de l'exécution, avant que quelqu'un ne supprime les logs de l'exécution 4412.
  2. Renouvelez tous les secrets Actions accessibles : tous les secrets lisibles par les workflows de payments-api, pas seulement les deux secrets AWS.
  3. Renouvelez les identifiants cloud et investiguez le cloud : désactivez la clé AWS et fouillez CloudTrail à partir de 02:40 UTC. Voir le pivot cloud et AWS Forensics.
  4. Passez en revue les modifications et exécutions de workflows : comparez .github/workflows sur ci/cache-fix, supprimez la branche et exigez une review CODEOWNERS pour les fichiers de workflow.
  5. Révoquez le jeton et réinitialisez le compte, après avoir réinstallé le poste de travail.
  6. Considérez le code cloné comme divulgué : analysez l'historique des 38 dépôts.
  7. Rétablissez la protection de branche et vérifiez ce qui est passé : le push de 03:06.
  8. Supprimez la persistance : supprimez la clé de déploiement backup-sync et recherchez tout autre élément créé depuis 203.0.113.66.

Ce que cet exemple ne montre pas

Les incidents réels sont plus désordonnés. Il n'y a ici ni prise de contrôle par un propriétaire, ni runner auto-hébergé, ni suppression du flux d'audit. L'attaquant n'a pas non plus étalé son activité sur plusieurs jours pour rester sous les seuils. Si une règle ne s'est pas déclenchée sur vos données, vérifiez les notes de couverture et ce que le journal d'audit n'enregistre pas avant de conclure.

À lire aussi

Articles liés

Runner auto-hébergé GitHub malveillant ou compromis : les événements du journal d'audit à vérifier, les preuves dans _diag, le périmètre et la reconstruction.
Comment les secrets GitHub Actions fuient malgré le masquage *** : workflows piégés, nouvelles branches, sorties encodées, actions tierces. Les preuves à lire.
Analyser hors ligne un export du journal d'audit GitHub : déposer JSON, événements Git et logs Actions, lire le verdict, trier les constats, pivoter, exporter.

Cet outil n'est ni affilié à GitHub, Inc. ou à Microsoft Corporation, ni approuvé ou sponsorisé par elles. GitHub et GitHub Actions sont des marques de GitHub, Inc. Les autres noms sont des marques de leurs propriétaires respectifs.