DevSecOps

wfx-loot : un voleur de secrets CI dans plus de 1 800 dépôts

Depuis le 10 novembre 2026, des comptes GitHub volés poussent un voleur de secrets dans les workflows de milliers de dépôts. Indicateurs, vérification et remédiation pour vos pipelines.

En bref. Depuis le 10 novembre 2026, un attaquant utilise des jetons GitHub volés pour pousser un script de vol de secrets d'intégration continue (CI) dans les dépôts auxquels ces jetons donnent un accès en écriture. Aikido Security, qui nomme la campagne wfx-loot, compte 4 837 comptes compromis ayant ouvert des pull requests de test dans 61 764 dépôts, et des indices d'exécution du script dans au moins 1 806 dépôts. L'attaquant n'exploite aucune faille de GitHub Actions : il utilise des identifiants valides, puis efface ses traces. Si le script a tourné chez vous, tous les secrets et rôles cloud accessibles au workflow sont à considérer comme volés.

Ce qui s'est passé

Aikido et StepSecurity ont publié leurs analyses le 12 novembre 2026, SafeDep la sienne dans la foulée. Selon Aikido, l'activité commence vers 12 h 45 UTC le 10 novembre. Les chiffres varient selon la méthode :

  • Aikido : 4 837 comptes compromis, sondes dans 61 764 dépôts, indices d'exécution dans au moins 1 806 dépôts (le résumé de l'article indique au moins 1 835 dépôts avec des identifiants exfiltrés), et au moins 50 comptes compromis qui semblent publier des paquets npm, Go, Packagist, PyPI ou crates ;
  • StepSecurity : à 7 h 40 UTC le 12 novembre, plus de 63 000 pull requests de sonde visibles dans la recherche GitHub, dont environ 90 % encore ouvertes ;
  • SafeDep : 8 093 dépôts publics (branche par défaut seulement, le total réel étant plus élevé selon SafeDep) ayant reçu des commits malveillants entre le 10 novembre à 12 h 46 UTC et le 12 novembre à 4 h 36 UTC, la campagne étant toujours active ; SecurityWeek précise que ce chiffre n'indique pas forcément une exécution.

Aikido précise que 10 431 pull requests visaient des dépôts que le compte ne possède pas, atteints via un accès de collaborateur ou d'organisation.

Des jetons d'application aussi. StepSecurity a relié 173 pull requests de sonde, ouvertes depuis 19 comptes, à des jetons émis pour l'application GitHub de Fly.io. L'entreprise dit ne pas savoir comment ces jetons ont été obtenus et n'avoir aucune preuve d'une compromission de l'infrastructure de Fly.io. La plupart de l'activité utilise d'autres identifiants, comme des jetons d'accès personnels (PAT).

Comment fonctionne l'attaque

Le principe tient en trois temps, décrits de façon concordante par Aikido et StepSecurity.

1. La sonde. Une pull request intitulée docs: dependency audit notes, depuis une branche wfx-docs, ajoute un fichier texte de deux lignes. Elle ne fait rien d'autre : elle confirme que le jeton peut écrire dans le dépôt. Si vous la voyez, le compte qui l'a ouverte est compromis.

2. La charge. L'attaquant pousse ensuite le même script d'environ 1 500 lignes, caché à l'un de ces endroits :

  • des étapes ajoutées à un workflow existant (commit ci: refresh build cache) ;
  • la fin d'un script shell que la CI exécute déjà, comme update.sh ;
  • un script caché .ci-xxxxxx.sh lancé par un script npm, le plus souvent postinstall (commits chore: add ci helper) ;
  • un nouveau workflow sur une branche jetable chore/xxxxxxxx (commit chore: add dependency audit workflow).

3. Le nettoyage. L'attaquant pousse un commit d'annulation (ci: restore, parfois ci: cleanup) en général en une minute environ (parfois quelques minutes) et supprime l'exécution du workflow avec ses journaux. Il reste souvent une seule trace : un numéro d'exécution manquant dans l'historique des Actions.

Ce que le script collecte. Les secrets et variables du dépôt, le GITHUB_TOKEN, la mémoire du processus de l'agent d'exécution (où les secrets sont déchiffrés, y compris ceux que le workflow n'a pas demandés), les fichiers d'identifiants AWS, Azure, GCP, Docker, Kubernetes, npm, PyPI, SSH et Vault, et les clés de fournisseurs d'IA et d'outils de code assistés par IA. Sur les agents d'exécution auto-hébergés, il récupère aussi les identifiants de métadonnées des instances cloud.

Ce qu'il fait ensuite. Avec le jeton OIDC du workflow (OpenID Connect, le mécanisme qui permet à un workflow de s'authentifier auprès d'un cloud sans clé stockée), il tente d'ouvrir des sessions AWS, GCP et Azure. Il prévoit trois mécanismes de persistance :

  • réécrire la politique de confiance d'un rôle AWS en "Principal": {"AWS": ""}, ce qui ouvre le rôle à tout compte AWS, et créer des clés d'accès longues durées pour des utilisateurs IAM (Identity and Access Management*, la gestion des identités d'AWS) ;
  • ajouter dans Azure AD (aujourd'hui Microsoft Entra ID, l'annuaire d'identités de Microsoft) des identifiants fédérés nommés wfx-ci-… qui font confiance au dépôt compromis ;
  • publier de faux statuts de vérification réussis pour franchir la protection de branche. Aikido explique que la protection de branche vérifie le nom du contexte, pas l'application qui publie le statut. StepSecurity précise que cette fonction n'était activée dans aucune des 101 copies qu'il a examinées.

L'exfiltration a changé. Les premières copies envoient les données en HTTP POST vers 194.150.166[.]244 ou 18.143.168[.]96, puis, à partir du 12 novembre vers 1 h 10 UTC, vers un troisième serveur, 153.75.82[.]159 (StepSecurity, SafeDep). StepSecurity observe à partir du 12 novembre vers 5 h 30 UTC des copies qui n'envoient plus qu'à un salon Telegram. Une liste de blocage construite sur les adresses IP du 10 novembre ne suffit donc plus.

Qui est concerné

  • Tout dépôt dans lequel un compte compromis peut écrire, y compris via une organisation ou un rôle de collaborateur.
  • Les comptes de bot autorisés à contourner la protection de branche : dans webdriverio/webdriverio, StepSecurity rapporte des commits poussés sous le compte du bot du projet, autorisé à contourner cette protection.
  • Les consommateurs de paquets publiés automatiquement. Versions identifiées : Packagist digitalelvis/neuronai-studio 3.14.3 ; Go github.com/onuragtas/docker-env v1.0.278 et v1.0.280, plus v1.0.282 selon SafeDep, qui précise que le module a été renommé github.com/onuragtas/redock et que le proxy Go sert les mêmes versions sous les deux chemins ; Go github.com/vkuznet/gocurl 0.0.0-20261111095532-8d5aad0cb0da. Pour docker-env v1.0.278 et v1.0.280 (Aikido, StepSecurity) et pour gocurl (StepSecurity), les analyses indiquent que la charge se trouve seulement dans un fichier de workflow, que les builds Go n'exécutent pas.
  • Les comptes déjà touchés par GhostAction en octobre, qu'Aikido juge plus exposés que la moyenne. Aikido estime toutefois probable qu'il s'agisse d'acteurs différents, et StepSecurity note que ce recoupement ne prouve pas un acteur unique.

Vérifier si vous êtes touché

Côté GitHub, sur tout dépôt où vous avez l'écriture, depuis le 10 novembre :

  • une pull request docs: dependency audit notes ou une branche wfx-docs ;
  • des commits ci: refresh build cache, chore: add ci helper, chore: add dependency audit workflow, ci: restore ou ci: cleanup ;
  • des branches chore/ suivies de huit caractères, des fichiers .ci-xxxxxx.sh ou .github/workflows/build-audit-xxxxxx.yml ;
  • un numéro d'exécution manquant dans l'onglet Actions juste après l'un de ces commits ;
  • dans les scripts et workflows, les variables WF_CALLBACK, WF_CTOKEN ou WF_TG_BOTS.

L'absence d'artefacts wfx-loot ou d'entrées de cache wfx- ne prouve rien : Aikido précise que ces canaux étaient désactivés dans cette campagne.

Côté cloud :

  • AWS : des politiques de confiance de rôle contenant "AWS": "", des clés d'accès IAM créées depuis le 10 novembre, des sessions nommées wfx- ;
  • Azure : des identifiants d'identité fédérée nommés wfx-ci-* sur vos applications ;
  • vos journaux de sortie réseau : des connexions vers les adresses ci-dessus ou vers api.telegram.org depuis un agent d'exécution.

Côté dépendances : cherchez les versions listées plus haut dans composer.lock et go.sum.

Remédier

  1. Révoquer le jeton du compte compromis, et chercher sa provenance sur les postes et services où il était stocké.
  2. Faire tourner tous les secrets accessibles aux workflows du dépôt touché, y compris les secrets d'organisation hérités, puisque le script lit la mémoire de l'agent d'exécution.
  3. Défaire la persistance cloud avant de considérer la rotation terminée : politiques de confiance AWS, clés IAM créées, identifiants fédérés Azure. Une rotation de secrets ne supprime pas ces portes.
  4. Reconstruire les paquets publiés entre le commit malveillant et son annulation, à partir d'un commit sain, comme le recommande StepSecurity.
  5. Fermer les pull requests de sonde et nettoyer les branches.

Durcir vos pipelines

Ces mesures sont des bonnes pratiques ; certaines découlent directement des analyses publiées.

  • Une liste d'autorisation de sortie réseau sur les agents d'exécution. StepSecurity souligne qu'elle arrête les deux modes d'exfiltration observés, parce qu'une IP nue et api.telegram.org n'ont pas leur place dans un build normal.
  • Des conditions strictes sur la confiance OIDC : limiter, dans la politique du rôle cloud, le dépôt, la branche ou l'environnement autorisés à l'endosser, pour qu'un workflow sur une branche jetable ne puisse pas obtenir de session.
  • Des permissions minimales pour le GITHUB_TOKEN et des jetons personnels à portée fine et à durée courte.
  • Aucun contournement de la protection de branche pour les comptes de bot, et des vérifications obligatoires liées à une application précise quand votre plateforme le permet.
  • Une alerte sur la suppression d'exécutions de workflow à partir du journal d'audit de l'organisation : c'est un geste de nettoyage récurrent de la campagne, et le trou qu'il laisse dans la numérotation est un signal en soi selon StepSecurity.
  • Des scripts d'installation npm désactivés en CI quand le projet n'en a pas besoin.

FAQ

Qu'est-ce que wfx-loot ?

Une campagne qui utilise des jetons GitHub volés pour insérer un script de vol de secrets dans les workflows et scripts de CI de milliers de dépôts, depuis le 10 novembre 2026. Le nom vient du nom que l'attaquant donne à son logiciel et du terme qu'il utilise pour les secrets volés.

GitHub Actions a-t-il une faille ?

Non selon StepSecurity : l'attaquant utilise des jetons valides de comptes de développeurs et de bots, comme le ferait un développeur.

Comment savoir si le script a tourné dans mon dépôt ?

Cherchez un commit ci: refresh build cache, chore: add ci helper ou chore: add dependency audit workflow depuis le 10 novembre, puis un numéro d'exécution manquant juste après dans l'onglet Actions. StepSecurity le considère comme le signe le plus fiable que le script a tourné.

Faire tourner les secrets suffit-il ?

Non. Le script peut ouvrir un rôle AWS à tous les comptes et ajouter des identifiants fédérés dans Azure. Ces accès survivent à la rotation et doivent être retirés à part.

Sources

  • Aikido Security, wfx-loot campaign pushes CI secret stealer to tens of thousands of repositories, 12 novembre 2026 : https://www.aikido.dev/blog/compromised-github-accounts-push-ci-secret-stealer-to-tens-of-thousands-of-repositories
  • StepSecurity, WFX Phantom: The GitHub Actions Secret Stealer That Deletes Its Tracks, 12 novembre 2026 : https://www.stepsecurity.io/blog/wfx-phantom-the-github-actions-secret-stealer
  • SafeDep, analyse de la campagne : https://safedep.io/blog/github-actions-wfx-credential-stealer
  • SecurityWeek, Attacker Targets 60,000 GitHub Repositories in Credential Theft Campaign, 12 novembre 2026 : https://www.securityweek.com/attacker-targets-60000-github-repositories-in-credential-theft-campaign/

Pour auditer les permissions, la confiance OIDC et la sortie réseau de vos pipelines, WeeSec accompagne les équipes en DevSecOps.

Un sujet connexe chez vous ?

20 minutes pour cadrer ensemble. Aucune offre commerciale envoyée à froid.

Réserver un échange Calendly