Le 5 novembre 2026, l'éditeur de sécurité applicative Apiiro a publié une analyse de 104 185 copies publiques du fichier .claude/settings.local.json trouvées sur GitHub. Ce fichier est celui dans lequel Claude Code, l'agent de programmation en ligne de commande d'Anthropic, enregistre les règles d'autorisation que l'on accepte en choisissant « Yes, and don't ask again » devant une commande. Résultat : 1 122 fichiers contiennent au moins un secret, soit 1 379 identifiants distincts sur les branches principales, et 2 539 secrets dans 1 994 dépôts une fois l'historique git, le fichier settings.json partagé et les transcriptions d'agent pris en compte. Parmi eux : des mots de passe de bases de données, des identifiants de connexion SSH, des clés API cloud, des jetons GitHub et npm. Le relevé a été fait entre le 1er et le 3 novembre 2026, et les 63 organisations identifiées ont été prévenues dans la foulée. Pour un administrateur qui pilote son VPS Linux, son serveur FiveM ou les sites web qu'il héberge sur un serveur virtuel avec Claude Code, la mécanique mérite d'être comprise, parce qu'elle ne tient qu'à une habitude de clavier.
Sources : analyse Apiiro, « Coding agents leaking secrets on GitHub » (5 novembre 2026) ; documentation officielle Claude Code, fichiers de configuration et permissions ; issue #5544 du dépôt claude-code (11 août 2025) ; étude ironPeak (17 février 2026).
Comment un mot de passe tapé une fois finit dans un fichier de configuration
Quand Claude Code veut exécuter une commande shell, il demande la permission. Le menu propose trois réponses : oui pour cette fois, oui et ne plus demander, non. La documentation d'Anthropic précise que pour une commande Bash, l'approbation permanente vaut « par dépôt et par commande ». Concrètement, Claude Code écrit une règle d'autorisation dans .claude/settings.local.json, à la racine du projet, sous la forme Bash(commande). Et la commande est enregistrée telle quelle. Si vous avez approuvé mysql -u fivem -pMotDePasse2026 fivem_db, la règle contient MotDePasse2026. Si vous avez approuvé un curl avec un en-tête Authorization: Bearer ..., le jeton est dedans. Si vous avez approuvé sshpass -p ou PGPASSWORD=..., pareil.
{
"permissions": {
"allow": [
"Bash(mysql -u fivem -pMotDePasse2026 fivem_db -e \"SHOW TABLES\")",
"Bash(curl -H \"Authorization: Bearer sk-live-abc123...\" https://api.exemple.fr/v1/servers)",
"Bash(sshpass -p 'Secret!' ssh root@203.0.113.10)"
]
}
}
Ce comportement n'est pas nouveau. Un utilisateur l'a signalé le 11 août 2025 dans l'issue #5544 du dépôt public de Claude Code, sous le titre « approved bash commands containing credentials are stored as is with plain text credentials in settings.local.json ». L'issue a été fermée automatiquement le 3 janvier 2026 avec le statut « not planned », faute d'activité. Apiiro indique avoir vérifié que le comportement est identique avec les modèles les plus récents, et que sur seize agents de programmation comparés, Claude Code est le seul confirmé comme sauvegardant par défaut la commande complète dans un fichier du projet.
Pourquoi le gitignore automatique n'a pas suffi
Anthropic avait prévu le problème du commit accidentel, mais à moitié. D'après sa documentation, la première fois que Claude Code écrit .claude/settings.local.json dans un dépôt git qui ne l'ignore pas déjà, il ajoute le motif **/.claude/settings.local.json au fichier d'exclusion global de l'utilisateur : core.excludesFile s'il est défini, sinon ~/.config/git/ignore. Ce fichier vit dans le répertoire personnel du développeur, pas dans le projet. Il n'est donc jamais versionné, ne suit pas le dépôt quand il est cloné sur une autre machine, ne protège pas un collègue qui n'a jamais lancé Claude Code, et ne retire pas un fichier déjà suivi par git. La doc le dit elle-même : si vous avez créé le fichier à la main, c'est à vous de l'ajouter au .gitignore.
| Situation | Le fichier est-il protégé ? | Pourquoi |
|---|---|---|
| Claude Code a créé le fichier sur votre machine, dépôt déjà initialisé | Oui, sur cette machine | Le motif est dans votre fichier d'exclusion global |
| Vous clonez le projet sur un VPS ou un second poste | Non | Le fichier d'exclusion global n'est pas dans le dépôt |
| Le dossier devient un dépôt git après la création du fichier | Non | Claude Code n'ajoute le motif que s'il écrit dans un dépôt existant |
Le fichier a été ajouté avec git add . avant la règle d'exclusion | Non | Une règle d'ignore n'agit pas sur un fichier déjà suivi |
| Vous avez créé le fichier à la main | Non | La doc demande de l'ajouter soi-même au .gitignore |
| Le fichier est supprimé du dépôt après un commit | Non | Le secret reste dans l'historique, les clones et les forks |
Les chiffres d'Apiiro confirment chaque ligne de ce tableau. Dans 539 des 1 105 dépôts dont l'historique a pu être tracé, un commit co-signé par Claude a modifié le fichier contenant les secrets : l'agent lui-même, en faisant un git add -A demandé par l'utilisateur, a embarqué sa propre configuration. L'historique git contient 734 secrets supplémentaires dans 509 dépôts, invisibles sur la branche principale mais toujours récupérables. 211 forks de 74 dépôts reprennent les mêmes secrets. Et le fichier partagé .claude/settings.json, celui que la documentation conseille justement de commiter pour l'équipe, contient lui aussi des secrets dans 298 copies sur 76 011.
Ce que contenaient les 1 122 fichiers
Apiiro a limité sa définition d'un « vrai secret » à deux cas : une valeur correspondant au format connu d'un fournisseur (préfixe de clé AWS, jeton GitHub, clé Supabase), ou un mot de passe associé à une adresse de serveur publique, après filtrage des valeurs factices et expirées. Les chercheurs n'ont testé aucun identifiant et n'ont contacté aucun serveur ; une organisation prévenue a cependant confirmé que sa clé était encore active. 63 organisations ont été identifiées, des startups aux éditeurs de logiciels en passant par des universités et des sociétés de paiement.
| Type de secret | Nombre | Ce que ça ouvre sur un serveur |
|---|---|---|
| Jetons de service API | 398 | API d'hébergeur, de registrar, de stockage objet : création ou suppression de ressources |
| Mots de passe de bases de données | 379 | Lecture et modification de la base MySQL ou PostgreSQL : comptes joueurs, économie du serveur, données clients |
| Clés API de modèles d'IA | 149 | Consommation facturée sur votre compte |
| Clés service-role Supabase | 122 | Accès complet au projet, contournement des règles de sécurité |
| Clés API Google | 110 | Selon la clé : Maps, Cloud, services facturés |
| Jetons de compte Supabase | 103 | Gestion du projet |
| Identifiants de connexion SSH | 43 | Shell sur un serveur public, souvent en root |
| Jetons GitHub, GitLab, npm | 42 | Publication de code ou de paquets en votre nom |
| Clés AWS | 23 | Infrastructure cloud complète |
Plus d'un tiers des secrets ouvrent directement une base de données. C'est la catégorie la plus parlante pour un propriétaire de serveur de jeu : la base MySQL d'un serveur FiveM contient les comptes, l'inventaire, les véhicules et l'argent de chaque joueur, et le mot de passe qui y donne accès est précisément celui que l'on tape dans une commande mysql ou mysqldump quand on demande à un agent de réparer une table. Autre enseignement : les outils de détection classiques passent à côté. Lancés sur les 1 122 fichiers, gitleaks en a repéré 564 et TruffleHog 643, et 215 fichiers ont échappé aux deux. La raison est simple : ces scanners cherchent des préfixes de clés structurés, pas un mot de passe libre collé après -p ou PGPASSWORD=.
Vérifier vos dépôts en cinq commandes
Première étape, savoir si vous êtes concerné. Dans chaque projet où vous avez utilisé Claude Code, sur votre poste comme sur le serveur dédié ou le VPS où le dépôt est cloné, lancez les commandes ci-dessous. Elles ne demandent que git, grep et find, présents sur n'importe quel Debian ou Ubuntu ; la dernière se lance avec sudo pour parcourir tout le disque, répertoires des autres utilisateurs compris :
# Le fichier est-il suivi par git ? (aucune sortie = non suivi, c'est ce qu'on veut)
git ls-files .claude/
# A-t-il existé dans l'historique, y compris sur des branches supprimées ?
git log --all --oneline -- .claude/settings.local.json .claude/settings.json
# Quelle règle l'ignore, et d'où vient-elle ? (silence = rien ne l'ignore)
git check-ignore -v .claude/settings.local.json
# Que contient-il aujourd'hui ? Repérez -p, PASSWORD=, Bearer, sshpass, token, key
grep -nEi 'password|passwd|-p[A-Za-z0-9]|bearer|token|secret|api[_-]?key|sshpass' .claude/settings.local.json
# Sur un serveur : tous les fichiers de ce type, tous projets et utilisateurs confondus
sudo find / -path '*/.claude/settings.local.json' -not -path '*/node_modules/*' 2>/dev/null
Si votre dépôt est public, complétez avec la recherche de code de GitHub en tapant path:.claude/settings.local.json suivi de votre nom d'utilisateur ou d'organisation. Pensez aussi aux dossiers des autres agents : Apiiro recommande de scanner .claude/, .cursor/, .gemini/ et .specstory/, historique compris. Les transcriptions de session de Claude Code, elles, sont stockées dans ~/.claude/projects/ sur la machine, hors du dépôt, mais elles contiennent chaque commande exécutée : si vous sauvegardez votre répertoire personnel sur un stockage partagé ou un dépôt de dotfiles, elles suivent.
Faire tourner les clés d'abord, nettoyer ensuite
L'ordre compte. Apiiro le résume en une formule : « rotate first, clean up second ». Un secret qui a été poussé une seule fois sur un dépôt public doit être considéré comme compromis, parce que des robots indexent GitHub en continu et que supprimer le fichier n'efface ni l'historique, ni les clones, ni les forks. Les trois rotations qui concernent le plus un administrateur de serveur :
# 1. Mot de passe de base de données : nouveau mot de passe, puis mise à jour du server.cfg,
# du .env ou du docker-compose.yml qui l'utilise
mysql -u root -p -e "ALTER USER 'fivem'@'localhost' IDENTIFIED BY 'NouveauMotDePasseGenere'; FLUSH PRIVILEGES;"
# 2. Clé SSH : nouvelle paire, dépôt de la clé publique, retrait de l'ancienne
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_2026 -C "admin@vps"
ssh-copy-id -i ~/.ssh/id_ed25519_2026.pub admin@203.0.113.10
# puis, sur le serveur, supprimer l'ancienne ligne de ~/.ssh/authorized_keys
# 3. Jetons d'API : révocation depuis l'interface du fournisseur (GitHub, hébergeur, cloud),
# puis génération d'un nouveau jeton avec le périmètre minimal
# Ensuite seulement : retirer le fichier du suivi sans le supprimer du disque
git rm --cached .claude/settings.local.json
echo ".claude/settings.local.json" >> .gitignore
git commit -m "Retire la configuration locale Claude Code du suivi"
# Et purger l'historique si le dépôt est public (réécrit tous les commits, à coordonner)
git filter-repo --path .claude/settings.local.json --invert-paths --force
Deux précisions pratiques. git filter-repo n'est pas livré avec git : sur Debian 12 et 13 comme sur Ubuntu 22.04 et 24.04, le paquet git-filter-repo est dans les dépôts officiels (sudo apt install git-filter-repo) ; sur une autre distribution, pip install git-filter-repo suffit, l'outil étant un script Python 3. Et une fois le mot de passe de la base changé, il faut redémarrer tout ce qui le lit : systemctl restart du service ou du conteneur qui charge le .env, redémarrage du serveur FiveM depuis txAdmin, sinon les connexions à la base échouent avec l'ancien identifiant et les requêtes SQL des scripts partent en erreur. Pour la rotation SSH, notre tutoriel configurer une clé SSH sans perdre l'accès détaille l'ordre des opérations qui évite de se retrouver enfermé dehors, et sécuriser un VPS Ubuntu avec SSH, UFW et Fail2ban couvre la désactivation des connexions par mot de passe. Si le mot de passe MySQL exposé était celui de root, créez plutôt un utilisateur MySQL dédié avec des droits limités à la base du serveur, et gardez root pour l'administration locale. Enfin, un journal auditd sur les fichiers sensibles permet de savoir, après coup, si quelqu'un a lu ou modifié le fichier de configuration ou le .env entre la fuite et la rotation.
Ne plus jamais mettre un secret dans une commande
La correction de fond ne dépend pas d'Anthropic : elle consiste à ne jamais faire apparaître un secret dans une ligne de commande, que ce soit vous ou un agent qui la tape. Chaque outil courant sur un serveur offre un moyen de lire ses identifiants ailleurs.
| Outil | À éviter (le secret est dans la règle enregistrée) | À préférer (la règle ne contient rien de sensible) |
|---|---|---|
| MySQL / MariaDB | mysql -u fivem -pSecret fivem_db | Fichier ~/.my.cnf en mode 600 avec une section [client], puis mysql fivem_db |
| PostgreSQL | PGPASSWORD=Secret psql -h ... | Fichier ~/.pgpass en mode 600, puis psql -h ... |
| SSH | sshpass -p Secret ssh root@ip | Clé ed25519 chargée dans l'agent SSH, mot de passe désactivé côté serveur |
| API HTTP | curl -H "Authorization: Bearer sk-live-..." | curl -H "Authorization: Bearer $API_TOKEN", la variable étant exportée dans votre shell, hors de la commande |
| Docker Compose | Mot de passe en clair dans la commande ou dans le YAML commité | Fichier .env ignoré par git, référencé par ${MYSQL_PASSWORD} dans le docker-compose.yml |
Le point important avec Claude Code : si la commande approuvée contient $API_TOKEN, c'est la chaîne $API_TOKEN qui est enregistrée dans la règle, pas sa valeur. Une variable d'environnement, un fichier d'identifiants en mode 600 ou un gestionnaire de secrets rendent donc le fichier settings.local.json inoffensif même s'il finit un jour sur GitHub. Trois habitudes complètent le dispositif. Ajouter .claude/settings.local.json au .gitignore de chaque projet, et au modèle de .gitignore de l'organisation, sans compter sur l'exclusion globale. Interdire explicitement la lecture des fichiers sensibles dans les permissions de Claude Code, avec des règles Read(./.env) et Read(./.env.*) dans la liste deny, comme le propose la documentation. Et relire ce que l'on approuve : « don't ask again » est confortable pour npm test ou docker compose logs, il ne l'est pas pour une commande qui transporte un identifiant. La fausse extension Claude Code distribuée avec une porte dérobée SSH, fin octobre, rappelait déjà que l'outillage autour des agents de programmation est devenu une cible à part entière.
Le cas d'un serveur FiveM ou Minecraft administré avec un agent
Les propriétaires de serveurs de jeu sont une population particulièrement exposée, pour une raison concrète : leur base de données est au centre de tout, et leurs scripts de maintenance manipulent son mot de passe en permanence. Un server.cfg FiveM contient la chaîne de connexion MySQL complète ; un script de sauvegarde lance mysqldump avec le mot de passe en argument ; un panel txAdmin affiche la configuration de la base. Demander à Claude Code de « vérifier pourquoi la table users est corrompue » se termine presque toujours par une commande mysql -p... que l'on approuve pour ne plus être dérangé. Si le dossier du serveur est versionné pour partager les ressources avec l'équipe de développement, ce qui est courant, le fichier de règles part avec.
Le remède tient en trois gestes. Mettre les identifiants de la base dans un fichier d'options MySQL en mode 600, et ne plus jamais les taper : le guide sauvegardes MySQL avec mysqldump et cron montre comment configurer ~/.my.cnf pour que les sauvegardes tournent sans mot de passe en ligne de commande. Ajouter .claude/ entier, ou au minimum settings.local.json, au .gitignore du dossier serveur, à côté du server.cfg qui ne devrait pas y être non plus. Et si vous faites tourner Claude Code ou un agent IA directement sur le VPS, lui créer un compte Linux et un utilisateur MySQL dédiés, avec des droits limités, plutôt que de le laisser travailler en root avec le mot de passe de la base dans chaque commande.
Même piège sur un serveur web : WordPress, FTP, SMTP, Plesk et sauvegardes
Le problème ne se limite pas aux bases de données de serveurs de jeu. Un VPS sert souvent aussi à héberger des sites web : un CMS comme WordPress derrière Apache ou nginx avec PHP, un espace FTP pour déposer les fichiers, un compte SMTP pour les mails du site, parfois un panneau Plesk pour administrer l'ensemble, et un script de sauvegarde (backup) vers un stockage distant. Chacun de ces outils accepte un identifiant en ligne de commande, donc chacun peut finir dans une règle d'autorisation. Le mot de passe MySQL qui apparaît dans une commande wp est en général celui du wp-config.php, c'est-à-dire aussi celui qui ouvre phpMyAdmin quand il est installé. Un jeton d'API de registrar permet de modifier les enregistrements DNS d'un nom de domaine, donc d'envoyer le trafic d'un site vers une autre adresse IP. Et la documentation de MySQL elle-même prévient que le mot de passe passé avec -p peut rester visible dans la liste des processus, avant même qu'un agent ne l'enregistre. Si vos sites tournent sur un hébergement web mutualisé plutôt que sur un VPS, vous n'avez pas ce fichier de règles à gérer, mais les identifiants FTP et SMTP tapés depuis votre poste suivent la même logique.
| Outil | À éviter (le secret est dans la règle enregistrée) | À préférer (la règle ne contient rien de sensible) |
|---|---|---|
| WP-CLI (WordPress) | wp user create admin2 admin@exemple.fr --user_pass='Secret!', wp config set DB_PASSWORD 'Secret!' | Omettre --user_pass : WP-CLI génère un mot de passe aléatoire et l'affiche une fois ; modifier wp-config.php dans un éditeur, hors agent |
| FTP / SFTP (lftp) | lftp -u deploy,Secret ftp.exemple.fr | Identifiants dans ~/.netrc en mode 600, ou variable LFTP_PASSWORD exportée avec --env-password ; mieux, SFTP avec une clé |
| SMTP (test d'envoi avec curl) | curl --ssl-reqd smtp://mail.exemple.fr --user 'contact@exemple.fr:Secret' --mail-from ... --mail-rcpt ... | curl -n : curl lit le couple machine / login / password dans ~/.netrc |
| Plesk (API REST) | curl -u admin:Secret https://203.0.113.10:8443/api/v2/domains | Clé créée sur le serveur avec plesk bin secret_key -c -ip-address <IP>, envoyée via -H "X-API-Key: $PLESK_KEY" |
| Docker (registre d'images) | docker login -u deploy -p Secret registry.exemple.fr | cat ~/.registry-pass | docker login -u deploy --password-stdin registry.exemple.fr, la forme recommandée par la doc Docker pour tenir le mot de passe hors de l'historique |
| Sauvegardes hors site (restic, rclone) | RESTIC_PASSWORD=Secret restic backup /var/www, rclone config create s3 s3 access_key_id ... secret_access_key ... | RESTIC_PASSWORD_FILE ou --password-file ; variables RCLONE_S3_ACCESS_KEY_ID et RCLONE_S3_SECRET_ACCESS_KEY chargées depuis un fichier d'environnement lu par cron |
Le fil conducteur est le même qu'avec MySQL : le secret vit dans un fichier en mode 600 (~/.netrc, ~/.my.cnf, un fichier d'environnement) ou dans une variable, et la commande approuvée n'y fait référence que par un nom. Pour les sauvegardes, nos tutoriels sauvegarder un VPS avec rsync vers un serveur distant et chiffrer ses sauvegardes hors site reposent sur une clé SSH et un fichier de mot de passe, jamais sur un secret en argument. Et si vous déployez vos sites avec Docker Compose, le fichier .env à côté du docker-compose.yml doit figurer dans le .gitignore au même titre que .claude/settings.local.json.
Ce qu'il faut retenir
- Le mécanisme : « Yes, and don't ask again » enregistre la commande approuvée mot pour mot dans
.claude/settings.local.json, secret compris. Signalé en août 2025, non corrigé au 5 novembre 2026. - L'ampleur : 1 122 fichiers publics avec au moins un secret, 1 379 identifiants distincts, 2 539 en comptant l'historique, le fichier partagé et les transcriptions. Un tiers sont des mots de passe de base de données.
- La protection par défaut : un fichier d'exclusion git global, propre à la machine, qui ne suit ni les clones, ni les forks, ni les collègues, et n'agit pas sur un fichier déjà suivi.
- Ce week-end :
git ls-files .claude/etgit log --all -- .claude/dans chaque projet ; rotation des mots de passe de base, clés SSH et jetons exposés ;git rm --cachedpuis ligne dans le.gitignore. - Pour la suite : plus aucun secret dans une commande, qu'elle vise MySQL, SSH, FTP, SMTP, Plesk, Docker ou un outil de sauvegarde. Fichiers d'identifiants en mode 600, variables d'environnement, règles
Readendenysur les.env, et un compte dédié pour l'agent.
FiveM
Minecraft
Rust
RedM
Hytale