Supprimer les secrets de l'historique Git après la fuite d'un prototype IA
Apprenez à supprimer des secrets de l'historique Git avec git filter-repo ou BFG, faire tourner les clés compromises et vérifier que votre dépôt est propre avant de reprendre.

Ce que signifie réellement une fuite de secret dans Git
Un « secret » est tout élément qui accorde un accès si quelqu'un d'autre l'obtient : clés API, tokens d'accès, mots de passe, chaînes de connexion à une base de données, certificats de signature et clés privées. Si cela peut permettre une connexion, débiter une carte, lire des données ou déployer du code, considérez-le comme un secret.
Lorsqu'un secret est commité dans Git, il fait désormais partie de l'historique du dépôt. Supprimer le fichier plus tard (ou l'ajouter à .gitignore) ne supprime pas le commit antérieur qui contient encore la valeur. Quiconque a accès au dépôt, à un fork, à un ancien clone ou à une copie mise en cache peut toujours la trouver. C'est pourquoi supprimer les secrets de l'historique est une tâche distincte de la suppression du fichier.
Les prototypes construits avec des outils IA fuient des secrets de manière prévisible. Un cas fréquent est le commit d'un fichier .env lors de la mise en place initiale, puis l'oubli. Un autre est le collage d'un extrait fonctionnel depuis le tableau de bord d'un fournisseur dans le code source « juste pour tester ». Les logs de debug peuvent être tout aussi problématiques s'ils affichent des tokens puis sont commis avec le reste.
Ce qui est en jeu va au-delà de l'embarras : accès non autorisé à des services (bases de données, stockage, fournisseurs d'authentification), facturation inattendue due à l'abus d'API, exposition ou modification de données clients, et perte de confiance si des utilisateurs ou partenaires le découvrent.
Un exemple concret : un prototype utilise une vraie clé Stripe, la commite une fois, puis passe à une nouvelle clé dans un commit ultérieur. Même si le code courant semble correct, la première clé est toujours dans l'historique, prête à être copiée.
Arrêter l'hémorragie d'abord
Au moment où un secret atterrit dans l'historique Git, traitez-le comme exposé. Même si le dépôt était privé, il a peut-être déjà été copié par le clone d'un coéquipier, un runner CI, un cache de build ou un outil IA ayant récupéré le code. N'attendez pas de confirmation. Agissez comme si un attaquant l'avait déjà.
Premier objectif : rendre la clé fuyante inutilisable. Révoquez-la, désactivez-la ou supprimez-la aussi vite que possible. Si le fournisseur permet de restreindre la portée, vous pouvez réduire les permissions immédiatement comme mesure temporaire, mais prévoyez de faire une rotation complète des identifiants après le nettoyage.
Ensuite, arrêtez tout ce qui pourrait continuer à utiliser ou diffuser le secret. Suspendez les jobs CI, les workflows planifiés, les environnements de prévisualisation et les déploiements automatiques. Ces éléments récupèrent souvent des variables d'environnement et génèrent des logs qui peuvent divulguer à nouveau des valeurs.
Avant de toucher à l'historique Git, mettez l'équipe d'accord :
- Révoquez ou désactivez l'identifiant exposé.
- Suspendez CI/déploiements et demandez à tout le monde de ne pas push, merger ou tagger tant que le plan n'est pas clair.
- Capturez la valeur exacte et où elle est apparue (nom de fichier et hash de commit) afin de supprimer la bonne chose.
- Tenez une note d'incident privée : ce qui a été tourné, quand, et quels services pourraient être affectés.
Exemple : si votre prototype a commité une clé Stripe et que la CI exécute des tests à chaque push, la pipeline peut continuer à appeler Stripe avec la clé fuyante et laisser des traces dans les logs. Suspendez la pipeline, révoquez la clé, puis passez à la réécriture de l'historique.
Inventaire de ce qu'il faut purger
Avant de réécrire l'historique, identifiez précisément ce qui a fuité et où cela apparaît. C'est ainsi que vous éviterez un « nettoyage » qui manque le vrai problème.
Notez chaque valeur fuyante que vous connaissez : clés API, URL de bases de données, secrets JWT, secrets clients OAuth, tokens de webhooks. Si vous n'avez qu'une capture d'écran ou un log d'erreur, extrayez le texte exact si possible.
Puis associez chaque secret à ses emplacements dans le dépôt. Ne regardez pas seulement la branche courante. Les secrets résident souvent dans d'anciens commits, des fichiers de test, des logs de debug, des données exportées et même des captures d'écran.
Les endroits courants à vérifier incluent les variantes de .env, les fichiers de config (comme settings.json ou docker-compose.yml), les dossiers de logs et tmp, les jeux de données de seed/sample, et la documentation/assets qui pourraient contenir des captures d'écran.
Une manière rapide de rechercher une chaîne connue dans votre copie de travail :
git grep -n "PASTE_PART_OF_KEY_HERE" -- .
Décidez de ce que vous devez supprimer :
- Chaînes exactes (idéal lorsque le token apparaît à plusieurs endroits)
- Fichiers entiers (idéal pour
.envou des données exportées qui n'auraient jamais dû être dans Git) - Dossiers entiers (idéal pour
logs/,tmp/, sauvegardes accidentelles)
Exemple : un prototype généré par IA peut avoir commité .env et aussi collé une URL de base de données de production dans config.ts. Ce sont deux cibles : supprimer .env de tout l'historique, et supprimer la chaîne URL exacte partout où elle apparaît.
Enfin, faites une sauvegarde sûre du dépôt avant de réécrire l'historique. Copiez tout le dossier ou créez un clone miroir pour pouvoir récupérer en cas de problème lors de la réécriture.
Étape par étape : purge avec git filter-repo
Si vous avez besoin de réécritures flexibles et fiables (plusieurs branches, tags, historique compliqué, ou plus d'un secret), git filter-repo est généralement le meilleur choix.
Commencez par un clone frais et faites une copie de sécurité. Fermez les PR ouvertes qui pourraient réintroduire les anciens commits.
1) Supprimer un fichier partout (exemple : un fichier env)
Si un prototype a accidentellement commité .env (ou un JSON de credentials), purgez-le par chemin :
git filter-repo --force --invert-paths --path .env
Cela réécrit chaque commit et supprime le fichier partout où il est apparu.
2) Supprimer ou remplacer des chaînes secrètes par contenu
Lorsque des secrets sont imbriqués dans le code, utilisez un fichier de remplacements. Créez replacements.txt comme ceci (côté gauche = ce qu'il faut matcher, côté droit = ce qu'il faut écrire) :
AKIAIOSFODNN7EXAMPLE==\u003eREMOVED
"api_key": "sk-live-123"==\u003e"api_key": "REMOVED"
Puis exécutez :
git filter-repo --force --replace-text replacements.txt
Avant de réécrire, décidez quelles branches et quels tags vous inclurez. Par défaut, filter-repo réécrit ce qui est dans votre clone local, alors fetchtez tout ce que vous prévoyez de garder (y compris les tags) et supprimez les branches que vous ne voulez pas publier.
Après la réécriture, confirmez que rien n'a cassé localement. Lancez votre build et vos tests, démarrez le serveur et faites une vérification rapide de bout en bout (par exemple, un flux de connexion basique). Puis recherchez à nouveau les anciens motifs de clés.
Étape par étape : purge avec BFG Repo-Cleaner
BFG Repo-Cleaner est adapté quand vous voulez un nettoyage rapide, surtout pour supprimer des fichiers entiers comme .env ou creds.json, ou pour remplacer des chaînes clés connues.
Avant de commencer, faites un clone miroir pour réécrire toutes les refs (branches et tags) en toute sécurité :
# 1) Mirror clone (works best for history rewrites)
git clone --mirror <your-repo-url> repo.git
cd repo.git
# 2) Remove whole files everywhere in history
bfg --delete-files .env
bfg --delete-files creds.json
# 3) Or replace leaked text (use a rules file)
# lines like: OLD_SECRET==>REMOVED
bfg --replace-text replacements.txt
# 4) Prune old objects BFG made unreachable
git reflog expire --expire=now --all
git gc --prune=now --aggressive
BFG réécrit les commits qui contenaient le secret, créant un nouvel historique où ces blobs ou chaînes ont disparu. Il ne fait pas la rotation des identifiants, et il ne peut pas vous protéger des copies du dépôt qu'une personne aurait déjà clonées.
Validez le résultat avant de pousser quoi que ce soit. Recherchez les tokens exacts que vous vous attendez à voir disparus, vérifiez que les fichiers sensibles n'existent plus dans aucun commit, et inspectez aussi les tags.
Pousser l'historique réécrit sans provoquer de chaos
Après avoir réécrit l'historique, le push est l'endroit où les équipes sont souvent surprises. L'objectif est simple : publier l'historique nettoyé, puis empêcher quiconque de réintroduire accidentellement les anciens commits.
Coordonnez un court gel (15 à 60 minutes) pendant lequel personne ne pousse, ne fusionne ou n'ouvre de nouvelles branches. Décidez ce que vous devez vraiment réécrire : généralement main et les branches longues utilisées par l'équipe. Les anciennes branches feature peuvent souvent être supprimées plutôt que réécrites.
Une séquence sûre :
- Annoncez le gel et confirmez que tout le monde est en pause.
- Assouplissez temporairement les règles de branche protégée si elles bloquent les force pushes.
- Force-pushez les branches réécrites (et les tags si nécessaire).
- Réactivez les protections de branche immédiatement.
- Dites à tout le monde exactement comment synchroniser leurs clones locaux.
Parce que les IDs de commit ont changé, vous devrez généralement faire un force push. Donnez aux collaborateurs deux options : re-cloner (le plus simple) ou faire un reset hard (plus rapide, mais facile à rater). Par exemple :
git fetch --all --prune
git checkout main
git reset --hard origin/main
Nettoyez aussi les endroits où les secrets ont tendance à traîner : anciens clones locaux, caches CI, artefacts de build et dépôts mirroirs.
Faire tourner les identifiants de manière sûre
Une fois qu'un secret a été commité, considérez-le comme compromis. Faites tourner chaque identifiant compromis que vous pouvez trouver, pas seulement celui qui a déclenché l'alerte.
Listez tout ce qui pourrait accorder un accès : clés API, mots de passe de base de données, fichiers de comptes de service, secrets clients OAuth, clés de signature JWT, identifiants SMTP, secrets de webhook, et toutes les clés « test » pointant vers des systèmes réels. Si le prototype a touché la production à un moment donné, incluez la production dans le plan de rotation.
Créez de nouveaux identifiants avec le moindre privilège. Préférez des tokens scoped et des durées de vie courtes quand le fournisseur le permet.
Un ordre sûr :
- Créez d'abord les nouveaux secrets, puis déployez-les aux applications et à la CI.
- Mettez à jour la production, la staging et les configs locales.
- Confirmez que l'application fonctionne de bout en bout.
- Révoquez les anciens secrets en dernier, puis surveillez les erreurs.
Après la rotation, gardez les secrets hors du dépôt pour de bon. Utilisez les variables de la plateforme d'hébergement ou un véritable coffre à secrets, et conservez les secrets locaux dans un fichier env non committé. Ajoutez des garde-fous comme un scan de secrets en pre-commit et des vérifications en CI.
Conservez un registre simple de ce qui a changé, quand, où la nouvelle valeur est stockée et qui en est responsable.
Vérifier que le dépôt est réellement propre
Considérez que vous n'avez pas fini tant que vous n'avez pas prouvé que la fuite a disparu partout où un développeur pourrait la récupérer.
Recherchez la valeur fuyée exacte, pas seulement le nom du fichier. Lancez la recherche sur tous les refs (branches et tags), pas seulement la branche courante.
git fetch --all --tags --prune
git grep -n "PASTE_LEAKED_VALUE_HERE" $(git rev-list --all)
Faites ensuite un scan plus large pour les formes communes de secrets. Cherchez des clés privées (BEGIN PRIVATE KEY), des longues chaînes de type base64, des JWT (trois segments séparés par des points), et tout préfixe spécifique au fournisseur que vous reconnaissez.
N'oubliez pas les logs CI et les artefacts de build. Même si le dépôt est propre, un secret peut encore être stocké dans des logs CI, des couches Docker en cache ou des artefacts uploadés. Ré-exécutez la dernière pipeline après avoir fait tourner les identifiants pour vous assurer que les logs n'impriment plus de valeurs sensibles.
Enfin, faites un test de clone depuis le remote dans un nouveau dossier ou une machine propre. Un dépôt peut sembler propre localement alors qu'un ancien ref distant expose encore le secret.
mkdir /tmp/clean-test && cd /tmp/clean-test
git clone <your-remote>
cd <repo>
git log --all -S "PASTE_LEAKED_VALUE_HERE" --oneline
Si vous trouvez encore des traces après une réécriture, cela signifie généralement qu'un tag, une branche distante ou un artefact CI contient encore l'ancien contenu.
Erreurs courantes qui font revenir les secrets
La plupart des fuites réapparaissent parce que le nettoyage n'a été fait que partiellement. Supprimer un fichier dans le dernier commit n'est pas la même chose que le supprimer de l'historique. Si quelqu'un peut encore checkout un ancien commit, le secret est toujours exposé.
Deux oublis fréquents :
- Oublier les tags et les anciennes branches. Un secret peut avoir disparu sur
mainmais vivre encore dans un tag de release ou une branche obsolète. - Supprimer un fichier mais pas la valeur. Les prototypes IA collent souvent la même clé à plusieurs endroits : fichiers de config, fixtures de test, scripts de build et logs.
Une autre cause fréquente est un coéquipier qui pousse depuis un ancien clone après la réécriture. Coordonnez un moment pour que tout le monde re-clone ou reset, et bloquez les merges jusqu'à ce que ce soit fait.
Exemple : fuite d'un prototype IA et plan de nettoyage réaliste
Une histoire courante : un fondateur construit rapidement un prototype dans Lovable ou Replit, commite tout sans remarquer qu'un .env s'est glissé. La démo marche, puis quelque chose cloche.
Les premiers signes sont souvent des conséquences réelles : une facture cloud qui grimpe pendant la nuit, des alertes de connexion étranges depuis un fournisseur d'email, ou un tableau de bord d'API montrant du trafic depuis des pays que vous ne servez pas.
Si le dépôt est public, supposez que les clés ont déjà été copiées. Faites immédiatement la rotation des identifiants, puis réécrivez l'historique Git pour supprimer le fichier et les tokens collés. Si le dépôt est privé, faites le même travail, et revoyez aussi qui avait accès (anciens prestataires, machines partagées, logs CI).
Si vous ne savez pas quelle clé a fuité, agissez comme si toutes l'avaient fait. Listez chaque système que le prototype a touché (base de données, fournisseur d'auth, paiements, email, stockage) et faites la rotation dans un ordre qui ne vous verrouillera pas hors du système.
Un plan réaliste :
- Geler les déploiements et suspendre la CI pour éviter toute propagation.
- Faire tourner d'abord les identifiants les plus dangereux (admin cloud, base de données, clés de paiement).
- Réécrire l'historique pour supprimer
.envet tout token commité, puis force-pusher. - Mettre l'app pour lire les secrets depuis une config sûre (variables d'environnement ou gestionnaire de secrets).
- Vérifier le résultat avec un clone frais et des recherches sur tout l'historique.
La communication est importante. Informez les parties prenantes en termes simples : ce qui s'est passé, ce qui a été exposé, ce que vous avez fait tourner et ce que vous avez vérifié. Donnez une courte chronologie et une note claire sur ce qui change pour elles.
Checklist rapide avant de reprendre le développement
Après une fuite, l'objectif est simple : rendre le secret volé inutile, l'effacer de l'historique et prouver qu'il a disparu avant d'écrire du nouveau code.
- Révoquez d'abord, puis mettez le travail en pause. Désactivez la clé/le token fuyé immédiatement et arrêtez les pushes pendant le nettoyage.
- Faites l'inventaire de ce qui a fui. Listez chaque nom de fichier et motif susceptible de contenir des identifiants.
- Réécrivez l'historique une fois, avec un seul outil. Choisissez soit
git filter-repo, soit BFG et exécutez-le sur un clone frais. - Poussez le nouvel historique et réinitialisez les collaborateurs. Force-pushez les branches/tags réécrits, puis faites re-cloner (ou reset hard) tout le monde.
- Faites tourner et relocalisez. Créez de nouveaux identifiants, sortez les secrets du dépôt et ajoutez des contrôles pour éviter les répétitions.
Faites une preuve finale : clonez dans un dossier tout neuf et scannez ce clone frais. Si le scan est propre et que l'app tourne avec les nouveaux identifiants, vous êtes revenu à un niveau de sécurité acceptable.
Étapes suivantes si le dépôt est en pagaille ou si l'app est déjà cassée
Parfois le problème dépasse la simple réécriture de l'historique. Si le dépôt est embrouillé, le build échoue, ou vous ne savez même pas ce qui a fuité, il est facile de perdre des jours en chirurgie Git pendant que l'app reste instable.
Signes qu'il est temps de demander de l'aide : plusieurs dépôts et forks introuvables, secrets dupliqués dans des fichiers générés, déploiements qui échouent après la réécriture, fuites multiples suspectées, ou une base de code difficile à modifier en toute sécurité (structure spaghetti, pas de tests, edits IA aléatoires).
Si vous avez hérité d'un prototype généré par IA, c'est précisément pour cela que FixMyMess (fixmymess.ai) existe : diagnostiquer la base de code et l'historique, réparer les problèmes logiques et de sécurité (comme une authentification cassée ou des secrets exposés), et préparer l'app à être déployée proprement. Ils proposent un audit de code gratuit pour cartographier les expositions avant tout engagement, et la plupart des travaux de remédiation sont réalisés en 48–72 heures.
Questions Fréquentes
If I deleted the `.env` file, why is the secret still “leaked”?
Cela signifie que le secret fait maintenant partie de l'historique du dépôt, pas seulement des fichiers actuels. Même si vous supprimez le fichier ou l'ajoutez à .gitignore, quiconque peut accéder à un ancien commit, à un fork ou à une copie antérieure peut toujours retrouver la valeur.
What should I do first when I discover a secret in Git history?
Révoquez ou désactivez immédiatement l'identifiant exposé afin que la valeur fuyée cesse de fonctionner. Ensuite, mettez en pause les CI/déploiements qui pourraient continuer à l'utiliser ou à l'enregistrer dans des logs, et seulement après cela réécrivez l'historique Git pour purger le secret des commits passés.
Is it still dangerous if the repo was private?
Oui. Les dépôts privés sont toujours susceptibles d'avoir été copiés via des clones de collègues, des runners CI, des caches de build, des dépôts miroir ou des machines partagées. Traitez tout secret commité dans Git comme compromis et faites-le tourner, même si vous pensez que l'accès était limité.
Should I use `git filter-repo` or BFG Repo-Cleaner?
git filter-repo est généralement le choix le plus sûr pour la plupart des cas car il est flexible pour plusieurs branches, tags et historiques complexes. BFG est souvent plus rapide et plus simple pour supprimer des fichiers entiers ou faire des remplacements textes directs, mais vous devez quand même valider les tags et exécuter les étapes de nettoyage après.
Why do I need to force-push after cleaning the repo?
Parce que la réécriture de l'historique change les IDs de commits, il faut forcer le push pour publier l'historique nettoyé. Planifiez un court gel, poussez les branches/tags réécrits une fois, puis demandez à tout le monde de re-cloner ou de faire un reset hard pour éviter de repousser les anciens commits.
How can I confirm the secret is truly gone after the rewrite?
Cherchez sur tous les refs, pas seulement la branche actuelle, et recherchez la valeur fuyée exacte ainsi que les motifs courants de secrets. Ensuite, faites un clone propre dans un nouveau dossier et recherchez à nouveau ; un clone frais est la manière la plus simple de détecter des branches distantes ou des tags qui exposeraient encore le secret.
If I rotate the key, do I still need to remove it from Git history?
La rotation rend la valeur volée inutile ; le nettoyage Git empêche la découverte future et la réutilisation accidentelle, mais il n'annule pas l'exposition antérieure. Donc oui : faites les deux — faites tourner les clés et nettoyez l'historique.
What usually causes secrets to come back after a cleanup?
Le plus souvent, on oublie les tags et les branches anciennes qui référencent encore l'ancien commit. Autre cause fréquente : un collègue qui pousse depuis un clone ancien après la réécriture, réintroduisant ainsi le secret. Assurez-vous que tout le monde re-clone ou fait un reset rigoureux.
How do I prevent AI-generated prototypes from leaking secrets again?
N'ajoutez pas de fichiers .env au dépôt et lisez les secrets depuis des variables d'environnement ou un gestionnaire de secrets fourni par votre plateforme d'hébergement. Ajoutez un scan de secrets en pre-commit et des vérifications en CI pour éviter qu'un token collé ou un log de debug ne se retrouve dans un commit.
Can FixMyMess help if the repo is tangled or I’m worried I’ll break things?
Oui. Si la base de code est désordonnée, que les builds échouent, ou que les secrets sont dupliqués dans des fichiers générés, une réécriture de l'historique peut devenir risquée et longue. FixMyMess peut auditer le dépôt, identifier les expositions, nettoyer l'historique en sécurité, faire tourner les identifiants sans casser les déploiements et remettre l'application en état de déploiement rapidement.