RSSI et consultant senior — WebGuard Agency
412 secrets en clair dans les pipelines de 9 clients — les 7 étapes qui les ont fait disparaître
TL;DR
- 412 secrets exploitables trouvés dans les chaînes d’intégration continue de 9 clients en un an d’audits. 73 % d’entre eux n’étaient plus visibles dans le code actuel : ils dormaient dans l’historique Git.
- L’ancienneté moyenne d’un secret jamais tourné était de 640 jours. Le record : une clé de service cloud créée en 2021, toujours valide, avec des droits d’administration complets sur la facturation.
- Une méthode en 7 étapes, applicable sur GitHub Actions, GitLab CI ou Jenkins, dans cet ordre précis : inventorier, classer, révoquer, centraliser, fédérer, faire tourner, verrouiller l’entrée.
- L’étape qui change tout est la cinquième : remplacer les secrets de longue durée par des identités fédérées à durée de vie courte. Elle supprime la catégorie de problème au lieu de la gérer.
Un secret dans une chaîne d’intégration continue, c’est n’importe quelle valeur qui donne un pouvoir : jeton de fournisseur cloud, clé d’interface applicative, mot de passe de base de données, clé de signature de paquet, jeton de robot de messagerie. En un an d’audits, nous en avons dénombré 412 exploitables sur les chaînes de 9 clients, tous secteurs confondus, de la PME de trente personnes au groupe de six cents.
Le chiffre qui a surpris nos interlocuteurs n’est pas le total. C’est celui-ci : 301 de ces secrets, soit 73 %, n’apparaissaient nulle part dans le code actuel. Ils avaient été retirés, proprement, parfois des années plus tôt. Ils dormaient dans l’historique du dépôt, où ils restent lisibles par quiconque obtient un accès en lecture. Voici la méthode que nous appliquons désormais systématiquement, dans cet ordre — et l’ordre compte plus que les outils.
Étape 1 — Inventorier l’historique complet, pas seulement l’état actuel
La première erreur consiste à lancer un scanner sur le dernier état du dépôt. C’est exactement ce que fait la majorité des équipes, et c’est ce qui produit le rapport rassurant qui masque 73 % du problème. Un secret retiré par un commit correctif reste présent dans l’objet Git d’origine, accessible pour toujours.
Passez donc un outil de détection sur l’intégralité de l’historique, toutes branches comprises, y compris les branches abandonnées et les étiquettes. Les outils libres du marché — détecteurs de secrets à base de motifs et d’entropie — font le travail correctement à condition qu’on leur donne le dépôt complet et non une copie superficielle.
Élargissez ensuite au-delà du code, car c’est là que se cachent les plus dangereux : variables d’environnement définies dans l’interface du moteur d’intégration, journaux d’exécution conservés, artefacts de compilation, images de conteneur intermédiaires, tickets et messages de discussion d’équipe. Sur les 412 secrets recensés, 64 ont été trouvés dans des journaux d’exécution, imprimés par une commande de débogage laissée active.
Le livrable de cette étape est une liste, pas un score. Une ligne par secret : où il a été trouvé, quel système il ouvre, qui l’a créé, à quelle date. Sans cette liste nominative, les étapes suivantes deviennent une discussion d’opinion.
Étape 2 — Classer par pouvoir de nuisance, jamais par ordre alphabétique
Un inventaire de 412 lignes paralyse une équipe. Il faut donc trancher immédiatement, avec un critère unique : qu’est-ce qu’un attaquant obtient dans les cinq minutes qui suivent l’utilisation de ce secret ? Trois catégories suffisent.
Niveau 1 — accès direct aux données ou aux droits. Jetons de fournisseur cloud, identifiants de base de données de production, clés de signature de paquets. Ce sont les 222 lignes rouges du graphique ci-dessus. Elles se traitent dans les quarante-huit heures.
Niveau 2 — accès à un service tiers au nom de l’entreprise. Passerelle de paiement, service d’envoi d’e-mails, hébergement de fichiers. Le risque est ici la fraude et l’usurpation d’identité de marque plutôt que la fuite de données. Traitement sous deux semaines.
Niveau 3 — portée limitée ou environnement jetable. Clé d’un bac à sable, jeton d’un service de test. À nettoyer, sans mobiliser l’équipe un vendredi soir.
Un détail opérationnel qui fait gagner des heures : ajoutez une colonne « propriétaire humain ». Un secret sans propriétaire identifié ne sera jamais tourné, parce que personne n’osera le révoquer de peur de casser une chaîne en production. C’est la cause première des clés de 640 jours.
Étape 3 — Révoquer d’abord, nettoyer l’historique ensuite
C’est l’inversion la plus importante de cette méthode, et celle que les équipes appliquent presque toujours à l’envers. Le réflexe naturel consiste à réécrire l’historique du dépôt pour effacer le secret, puis à le remplacer. C’est l’ordre le plus coûteux et le moins efficace.
Un secret exposé doit être considéré comme compromis, définitivement. Vous ne saurez jamais qui a cloné le dépôt, qui a lu le journal d’exécution, quelle copie de sauvegarde a été indexée. La seule action qui restaure la sécurité est la révocation : le secret cesse d’ouvrir quoi que ce soit. Une fois révoqué, sa présence dans l’historique devient un détail cosmétique.
La séquence correcte est donc : créer le nouveau secret, le déployer dans le coffre, vérifier que la chaîne fonctionne avec, puis révoquer l’ancien, et enfin — si le contexte l’exige, par exemple pour un dépôt qui va devenir public — réécrire l’historique. Cette dernière opération casse tous les clones existants et impose une coordination avec l’ensemble de l’équipe : elle mérite d’être planifiée, pas improvisée.
Erreur classique — Le commit « suppression de la clé » qui sert de balise à l’attaquant
Nous voyons régulièrement des messages de commit explicites du type « retrait de la clé API en dur ». C’est une signalisation parfaite : n’importe qui parcourant l’historique sait exactement à quel commit précédent se rendre pour récupérer la valeur. Si vous devez retirer un secret sans pouvoir le révoquer immédiatement, ne l’annoncez pas dans le message. Et révoquez-le dans l’heure.
Étape 4 — Centraliser dans un coffre, avec une règle de nommage stricte
Le choix de l’outil compte moins que la discipline qu’il impose. Un gestionnaire de secrets dédié, le service natif de votre fournisseur cloud, ou un chiffrement de fichiers de configuration versionnés : les trois fonctionnent. Ce qui ne fonctionne pas, c’est la coexistence des trois avec des périmètres flous, situation dans laquelle nous trouvons la majorité des PME.
Imposez une convention de nommage explicite, du type environnement/service/usage. Elle paraît bureaucratique le premier jour, elle devient indispensable le jour où il faut répondre en urgence à la question « quels secrets donnent accès à la production ? ». Un nom qui ne permet pas de répondre à cette question sans ouvrir la valeur est un mauvais nom.
Activez la journalisation des accès au coffre dès le premier jour. C’est la seule source qui vous dira, plus tard, quel secret a réellement été lu, par quelle chaîne et à quelle heure. Sans elle, une investigation après incident se réduit à des suppositions.
Enfin, restreignez la portée : une chaîne de compilation d’un dépôt ne doit accéder qu’aux secrets de ce dépôt et de son environnement cible. Le partage d’un même jeton entre douze projets, parce que c’était plus simple à configurer, multiplie par douze la surface exposée par une seule compromission.
Combien de secrets dorment dans votre historique Git ?
Nous passons vos dépôts, vos journaux d’exécution et vos images de conteneur au crible, puis nous livrons la liste priorisée et le plan de rotation. Comptez trois jours. Téléphone : +33 6 32 64 24 80.
Lance-toiÉtape 5 — Remplacer les secrets de longue durée par des identités fédérées
Les quatre premières étapes gèrent le problème. Celle-ci le supprime, et c’est pour cette raison qu’elle mérite l’essentiel de votre budget d’attention.
Le principe : votre moteur d’intégration continue prouve son identité au fournisseur cloud au moment de l’exécution, via un jeton signé de courte durée, et reçoit en retour des droits temporaires. Aucun secret de longue durée n’est stocké nulle part — ni dans le dépôt, ni dans le coffre, ni dans l’interface du moteur. GitHub Actions, GitLab CI et les principaux fournisseurs cloud prennent tous ce mécanisme en charge nativement depuis plusieurs années.
L’effet sur le risque n’est pas incrémental. Un jeton de fournisseur cloud statique volé reste exploitable jusqu’à sa rotation, c’est-à-dire — dans les faits que nous mesurons — 640 jours en moyenne. Un jeton fédéré volé pendant une exécution expire au bout de soixante minutes. La fenêtre d’exploitation est environ quinze mille fois plus courte.
Le point de vigilance porte sur la condition de confiance. Le fournisseur doit vérifier non seulement que la demande vient bien de votre organisation, mais aussi de quel dépôt et de quelle branche. Une condition trop permissive — acceptant n’importe quel dépôt de l’organisation — permet à un contributeur d’un projet secondaire d’obtenir des droits sur la production. C’est une erreur de configuration que nous rencontrons souvent, et qui annule une grande partie du bénéfice.
Étape 6 — Automatiser la rotation de ce qui ne peut pas être fédéré
Une partie des secrets résistera : services tiers sans support des identités fédérées, systèmes internes anciens, comptes de service partagés. Pour ceux-là, la rotation manuelle « une fois par an » n’a jamais tenu chez aucun de nos clients. Elle est reportée au premier incident, puis oubliée.
La seule rotation qui tient est celle qui s’exécute sans décision humaine. Définissez une durée de vie par catégorie — trente jours pour un niveau 1, quatre-vingt-dix pour un niveau 2 — et faites porter la rotation par une tâche planifiée qui génère le nouveau secret, le publie dans le coffre et révoque l’ancien après une fenêtre de recouvrement.
Prévoyez explicitement cette fenêtre de recouvrement, pendant laquelle l’ancien et le nouveau secret sont valides simultanément. C’est ce qui évite l’interruption de service à chaque rotation — et donc ce qui évite que l’équipe désactive l’automatisation au bout de trois semaines. Une rotation qui casse la production sera débranchée, quelle que soit la politique affichée.
Surveillez enfin l’âge du plus vieux secret actif, et affichez cette valeur unique sur le tableau de bord de l’équipe. C’est un indicateur honnête, difficile à contourner, et infiniment plus utile qu’un pourcentage de conformité. Le même raisonnement d’indicateur mesurable s’applique aux exigences de sécurité opposables décrites dans notre méthode de mise en conformité NIS2 en 8 étapes.
Étape 7 — Verrouiller l’entrée pour ne jamais recommencer
Sans cette dernière étape, vous referez l’inventaire dans dix-huit mois avec des chiffres comparables. Le verrouillage se joue sur deux niveaux, et les deux sont nécessaires.
Côté poste de développement, un contrôle avant commit. Il refuse localement l’enregistrement d’une valeur ressemblant à un secret. C’est le filet le plus confortable pour les équipes, parce qu’il intervient avant toute publication — mais il se contourne d’une option en ligne de commande, il ne peut donc pas être le seul.
Côté serveur, un contrôle bloquant dans la chaîne. Non pas un avertissement dans un rapport que personne ne lit : un échec de la chaîne, qui empêche la fusion. C’est la seule mesure qui tient dans la durée, parce qu’elle ne repose sur la vigilance de personne.
Acceptez le coût des faux positifs des premières semaines et tenez la ligne : une exception documentée, avec un propriétaire et une date d’expiration, plutôt qu’une désactivation globale de la règle. La discipline des exceptions datées est exactement celle que nous appliquons sur les périmètres de test d’intrusion, dont nous détaillons la construction et le budget dans notre guide des prix d’un audit pentest pour PME.
Ce que la méthode a donné en pratique
Sur les 9 chaînes reprises, la première passe — étapes 1 à 3 — a duré entre trois et neuf jours selon l’ancienneté des dépôts. Les 222 secrets de niveau 1 ont tous été révoqués dans la première semaine. Deux interruptions de service ont eu lieu, toutes deux liées à un secret partagé entre plusieurs projets sans que personne ne le sache : c’est le prix à payer pour découvrir la vraie cartographie, et il vaut mieux le payer un mardi matin qu’au milieu d’un incident.
La bascule vers les identités fédérées, étape 5, a demandé entre deux et six semaines. Elle a été plus rapide chez les équipes qui avaient déjà normalisé leurs environnements, et plus lente là où chaque projet avait sa propre convention. Le sujet touche directement à la structuration des chaînes de livraison, que nos confrères de D-Open traitent régulièrement côté ingénierie, et il devient critique dès qu’on branche des agents ou des plateformes d’IA sur les dépôts internes — un angle couvert par Plug-Tech.
Douze mois plus tard, l’indicateur qui a le mieux résisté est l’âge du plus vieux secret actif. Il est passé d’une moyenne de 640 jours à moins de 40 sur huit des neuf chaînes. La neuvième conserve deux secrets anciens, documentés, liés à un système que l’éditeur refuse de faire évoluer : c’est une exception assumée, avec un propriétaire et une date. C’est très exactement le résultat recherché — pas un tableau parfait, mais une liste courte de compromis que quelqu’un a signés.
Questions fréquentes
Vous ne trouvez pas la réponse à votre question ?
Passons vos pipelines au crible en trois jours
Inventaire complet de l’historique Git, des journaux d’exécution et des images de conteneur, liste priorisée par pouvoir de nuisance et plan de rotation prêt à appliquer. Téléphone : +33 6 32 64 24 80.
Lance-toiVeille cybersecurite
Recevez chaque semaine les dernieres menaces, vulnerabilites et bonnes pratiques directement dans votre boite mail.
Pas de spam. Desinscription en un clic. Environ 1 email par semaine.
— Pret a renforcer votre cybersecurite ?
Rejoignez les entreprises qui font confiance a WebGuard Agency pour proteger leurs actifs numeriques. Premier audit offert.