Donner un secret à un agent de code sans jamais le mettre dans le prompt
Un agent a besoin d'une clé Stripe ou d'un mot de passe de base pour lancer sa commande. Collez-la dans la conversation et elle part dans le transcript sur votre disque, chez le fournisseur du modèle, parfois dans un commit. La règle à laquelle on est arrivés après trois de nos propres erreurs : un secret atteint un agent par une variable d'environnement, et par rien d'autre.
La situation est toujours la même. Un agent est au milieu d'une tâche, il doit appeler votre API Stripe de test, lancer une migration sur la base de staging, ou pousser vers un registre privé. Il demande la clé. Vous avez la clé dans votre gestionnaire de mots de passe, l'agent attend, et la chose la plus rapide du monde est de la coller dans la conversation.
Ce collage est le moment où la clé sort de votre contrôle. Pas parce que le modèle est malveillant, mais parce qu'un prompt est un objet stocké et transmis : il part dans un fichier de transcript sur votre disque, il part chez le fournisseur du modèle, et il est recopié par chaque relance et chaque sous-agent qui hérite de la conversation.
On développe AgentsRoom, une app desktop qui fait tourner des agents de code, donc on a dû régler ça pour nous-mêmes. On s'est trompés trois fois en septembre 2026. Voici la règle à laquelle on est arrivés, les trois erreurs qui l'ont produite, et comment l'appliquer que vous utilisiez notre app ou non.
La réponse courte
- Un secret atteint un agent par une variable d'environnement, et par rien d'autre. Ni un message, ni un ticket, ni un skill, ni une option de ligne de commande.
- L'agent utilise
$NOM, jamais la valeur. Le shell la remplace au moment où la commande tourne. - Rangez la valeur une fois, hors du dépôt, chiffrée par le trousseau de votre système, et référencez-la par son nom partout ailleurs.
- Un secret passé dans une conversation est brûlé. Changez-le, puis faites le ménage.
- Le masquage est un filet, pas un plan. Il attrape ce qui ressemble à une clé, pas un mot de passe de base qui se lit comme un mot.
Pourquoi ce collage est pire qu'il n'en a l'air
Trois choses arrivent en même temps, et seule la première est visible.
Ça part chez le fournisseur du modèle. C'est la partie que tout le monde voit. Votre clé est maintenant dans un corps de requête sur l'infrastructure de quelqu'un d'autre, à l'intérieur d'une conversation que vous ne pouvez pas modifier.
Ça part sur votre disque, en clair. Claude Code, Codex, Antigravity CLI et les autres gardent un transcript de la conversation pour pouvoir la reprendre. Ce fichier est dans votre dossier personnel, non chiffré, aussi longtemps que le CLI garde son historique. Cherchez une fois la chaîne sk- dans vos transcripts et regardez ce qui remonte.
Ça se propage sur les côtés. La conversation est la mémoire de l'agent, donc tout ce qui copie la conversation copie la clé : une session reprise, un agent forké, un sous-agent lancé avec le contexte du parent, un résumé écrit dans un fichier du projet. On a vu une clé voyager d'un message vers une description de ticket, puis vers le premier message d'un deuxième agent, sans que personne ne fasse rien de mal.
Et le filet habituel ne tient pas. Le masquage en sortie travaille par motif : sk-…, glpat-…, une forme de JWT. Il ne peut pas savoir que jeudi-port-71 est le mot de passe de votre base de staging. Dans notre propre app, on masque les valeurs reconnues dans la sortie des terminaux, et on considère quand même ça comme un filet sous le trapèze, pas comme le trapèze.
La règle de la porte unique
La voici, en une ligne : un identifiant atteint un agent par une variable d'environnement du process où il tourne, et par aucun autre canal.
Tout le reste est du texte littéral. Un message que vous tapez, une description de ticket, un fichier de skill, un system prompt, une option de ligne de commande : tout ça est lu par un humain ou par un modèle, donc un secret écrit là est un secret publié.
La ligne de commande mérite sa propre phrase, parce qu'elle paraît plus sûre qu'un message et ne l'est pas. Une valeur dans --api-key=… est visible par tous les process de la machine avec ps, elle atterrit dans l'historique de votre shell, elle est journalisée par tout ce qui enregistre la commande lancée, et elle réapparaît dans les outils de diagnostic qui vous réaffichent la ligne du process. Une variable d'environnement d'un process est lisible par ce process et par root. Surface plus petite, même confort.
L'agent, lui, n'a jamais besoin de la valeur. Il a besoin d'écrire ceci :
curl -H "Authorization: Bearer $STRIPE_SECRET_KEY" https://api.stripe.com/v1/charges
Le shell remplace $STRIPE_SECRET_KEY à l'exécution. L'agent a écrit dix-sept caractères et un signe dollar. Son transcript contient dix-sept caractères et un signe dollar.
Comment ça marche dans notre app
Le mécanisme compte moins que la forme, mais la forme est plus facile à copier quand on en voit une mise en œuvre.
Un coffre, un fichier. AgentsRoom garde les secrets dans un seul fichier de votre dossier personnel, en mode 0600, chiffré par le trousseau du système d'exploitation, réaffirmé à chaque écriture. Rien n'est synchronisé vers un serveur, et rien ne passe sur un autre ordinateur : un secret appartient à la machine qui le détient. Si le trousseau est indisponible, l'enregistrement échoue au lieu de retomber en clair.
Vous enregistrez une valeur une fois. Commandes et connexions > Secrets, dans n'importe quel projet. Un nom (lettres, chiffres, point, tiret, souligné, 64 caractères, donc utilisable tel quel comme nom de variable d'environnement) et une valeur, tapée dans un champ mot de passe. La ligne qui apparaît montre le nom et sa référence, {{secret:STRIPE_SECRET_KEY}}, et un bouton qui copie la référence. Il n'y a pas de bouton « révéler » ni de copie de valeur, parce qu'il n'existe aucun chemin de code qui rende une valeur à l'interface.
Vous la référencez là où l'environnement est construit. Modifier l'agent > Avancé > Variables d'environnement, ou les réglages du projet, ou ceux du provider, ou une ligne de commande de dev :
STRIPE_SECRET_KEY={{secret:STRIPE_SECRET_KEY}}
Au lancement, le process principal substitue la valeur dans l'environnement du terminal qu'il s'apprête à créer. L'interface ne la voit jamais, l'agent ne la voit jamais, le téléphone ne la voit jamais. La page Gestionnaire de secrets montre les écrans.
L'agent découvre des noms, pas des valeurs. Un agent branché sur nos outils MCP peut appeler secrets_list et récupérer la liste des noms présents sur cette machine. C'est assez pour qu'il serve à quelque chose : il peut dire « vous avez un STRIPE_SECRET_KEY enregistré, ajoutez STRIPE_SECRET_KEY={{secret:STRIPE_SECRET_KEY}} à l'environnement de cet agent et j'utiliserai $STRIPE_SECRET_KEY ». Il ne peut pas lire la valeur, même en exécutant une commande qui s'en sert.
Trois erreurs qu'on a livrées
La règle ci-dessus a l'air évidente une fois écrite. C'est la cicatrice de trois bugs, tous en septembre 2026, tous signalés par des utilisateurs.
Une référence citée dans un ticket ressortait résolue
19 septembre. Robert avait documenté un mapping dans la description d'un ticket, le parfaitement raisonnable STRIPE_SECRET_KEY={{secret:STRIPE_SECRET_KEY}}, pour que la personne qui prendrait le ticket sache quoi régler. Relu par l'API, le ticket renvoyait la référence intacte. Mais l'agent lancé depuis ce ticket recevait la valeur dans son premier message.
La cause était un détail de plomberie avec une vraie conséquence. Le brief d'un ticket devient le premier prompt de l'agent, qui voyageait dans une variable d'environnement de la commande de lancement. Notre résolveur substituait toutes les valeurs d'environnement, donc il substituait aussi le prompt. La clé est partie sur le disque et chez le fournisseur du modèle. Rotation obligatoire, aucun moyen d'y couper.
Le correctif a consisté à rendre la commande de lancement d'un agent littérale : quand l'environnement porte un identifiant d'agent, la variable qui contient le premier prompt n'est pas touchée. Une commande de dev qui utilise la même variable n'a pas d'identifiant d'agent et résout comme avant. On a accepté un effet de bord exprès : une référence tapée dans les options CLI d'un agent ne se résout plus non plus, ce qui est correct, puisqu'une ligne de commande finit de toute façon dans ps et dans les journaux.
La leçon : la porte doit être étroite exprès. « Substituer partout où ça pourrait servir » est exactement comme un secret finit là où il ne devrait jamais être.
Une référence collée dans un message, qui ne se résout jamais
22 septembre. Cs040618 a signalé le problème inverse : « je colle la référence dans la conversation, mais l'agent n'arrive pas à comprendre ce qu'est cette clé ».
Ce n'est pas un bug. Un message est du texte littéral par conception, ce qui est exactement le correctif de trois jours plus tôt. Mais rien dans l'app ne le disait au moment du geste, et l'agent, recevant {{secret:…}} dans un message, n'avait aucune idée de quoi répondre.
Trois corrections, toutes pour dire où est la porte : une suggestion qui se déclenche quand on colle une référence dans le champ de saisie et qui pointe vers les variables d'environnement, une aide au-dessus de la liste des secrets qui nomme les trois champs où une référence est substituée et dit « jamais dans un message », et une ligne dans les instructions de l'agent lui-même qui lui dit quoi répondre quand une référence lui arrive dans un message.
« Réglages > Secrets » n'existait pas
28 septembre. L'agent de Mohammad a déposé un signalement : l'utilisateur dit avoir ajouté OTPIQ_API_KEY dans Réglages > Secrets, l'avoir enregistré plusieurs fois en trente minutes, et secrets_list renvoie toujours les trois mêmes anciens secrets.
Le chemin d'enregistrement allait bien. Le secret n'était jamais arrivé dans le coffre, parce qu'il n'y a pas de page Secrets dans les réglages. Six textes d'aide de l'app desktop, une page de ce site et les instructions de l'agent envoyaient tous vers un écran qui n'existait pas. Ce qui existe bien dans les réglages, c'est le bloc des variables d'environnement : c'est donc là qu'il a tapé le jeton, entre accolades, ce qui n'est pas une référence. Jamais substitué, envoyé tel quel à l'agent, et synchronisé avec le projet : le jeton a quitté la machine.
On a corrigé les textes pour qu'ils nomment le vrai chemin, fait dire aux outils destinés aux agents où l'on ajoute un secret, et ajouté un contrôle sur le bloc d'environnement qui signale un identifiant tapé en clair, un nom entre accolades qui n'est pas une référence, et une référence à un secret absent de cette machine.
La leçon n'a rien à voir avec les secrets : un chemin faux dans un texte d'aide est un bug de sécurité. Il envoie l'utilisateur vers le champ le plus proche qui a l'air d'être le bon.
Si vous n'utilisez pas AgentsRoom
La règle voyage. Prenez celle de ces options qui correspond à votre installation ; elles arrivent toutes au même endroit, une variable d'environnement dans le process où tourne l'agent.
- Le CLI d'un gestionnaire de mots de passe.
op run -- claudeavec 1Password, ou l'équivalent chez Bitwarden et Doppler : l'outil lit des références dans un gabarit, injecte les vraies valeurs dans l'environnement du process fils, et rien n'est écrit sur le disque. direnvavec un.envrcgitignoré. Simple, local, par dossier. Ajoutez.envrcet.env*au.gitignoreavant la première valeur, pas après.- Un fichier
.envque l'agent ne lit jamais. Gardez-le hors du dépôt et chargez-le dans le shell qui lance l'agent. Si le fichier est dans le dépôt, l'agent finira par l'ouvrir, le citer dans un message, et vous voilà revenu au point de départ. - Identifiants cloud : prenez-les éphémères. GitHub OIDC en CI plutôt que des clés AWS à longue durée de vie, et une identité de charge de travail plutôt qu'un fichier de clé de compte de service.
Quoi que vous choisissiez, mettez la règle dans les instructions de l'agent, pour qu'il arrête de demander. Un paragraphe dans CLAUDE.md ou AGENTS.md suffit : ne jamais demander la valeur d'un identifiant, ne jamais en écrire un dans un fichier, utiliser $NOM et dire à l'utilisateur quelle variable régler. On publie un petit skill qui dit exactement ça, et il fait cinq lignes.
Si une clé est déjà passée dans une conversation
Dans cet ordre, et la première étape n'est pas facultative.
- Changez-la. Un prompt ne se reprend pas. Considérez la valeur comme compromise et émettez-en une nouvelle.
- Retrouvez les transcripts. Les CLI gardent les fichiers de conversation dans votre dossier personnel. Cherchez-y l'ancienne valeur et supprimez ou tronquez ce qui correspond.
- Vérifiez les endroits qui copient du texte. L'historique du gestionnaire de presse-papiers, le ticket ou l'issue où l'agent a été briefé, tout résumé que l'agent a écrit dans le dépôt, et
git log -psi l'agent a commité pendant qu'il la détenait. - Et seulement là, montez la porte. Nouvelle valeur derrière une variable d'environnement, référence par son nom, et instructions de l'agent mises à jour pour que le prochain ne demande pas.
L'étape 4 en dernier, parce qu'un mécanisme propre autour d'une clé fuitée n'est qu'une fuite mieux rangée.
Les questions que les gens posent vraiment
Pourquoi ne jamais mettre une clé d'API dans un prompt adressé à un agent IA ?
Parce qu'un prompt est stocké et transmis. Claude Code, Codex et les autres CLI écrivent la conversation dans un fichier de transcript sur votre disque, et le message part chez le fournisseur du modèle. De là, la clé est aussi dans l'historique de votre presse-papiers, dans tout journal qui recopie le message, et dans les relances et les sous-agents qui héritent de la conversation. Le masquage par motif attrape ce qui ressemble à sk- ou glpat-, pas un mot de passe de base qui ressemble à un mot ordinaire.
Comment un agent de code utilise-t-il un secret qu'il ne peut pas lire ?
Par une variable d'environnement. Vous mettez la valeur dans une variable d'environnement du process où tourne l'agent, et l'agent écrit $STRIPE_SECRET_KEY dans la commande au lieu de la valeur. Le shell la remplace au moment de l'exécution. L'agent ne voit jamais les caractères, donc ils n'entrent jamais dans sa conversation ni dans son transcript.
Puis-je passer le secret en argument de ligne de commande à la place ?
Vous pouvez, et vous ne devriez pas. Une ligne de commande est visible par tous les process de la machine avec ps, elle entre dans l'historique du shell, dans les journaux de process, et dans tout outil de diagnostic qui relit la commande lancée. Une variable d'environnement d'un seul process est lisible par ce process et par root, c'est une surface bien plus petite.
Où AgentsRoom range-t-il les secrets que les agents utilisent ?
Dans un seul fichier de votre dossier personnel, en mode 0600, chiffré par le trousseau de votre système d'exploitation, sur cette machine uniquement. Rien n'est synchronisé vers un serveur, et aucun bouton ne réaffiche une valeur. L'app montre des noms, l'agent voit des noms, et la valeur n'est déchiffrée que dans le process principal, au moment où un terminal ou une commande démarre.
Que se passe-t-il si je colle une référence de secret dans un message à l'agent ?
Rien n'est substitué, et c'est voulu. Un message, une description de ticket, un skill et un system prompt sont du texte littéral : une référence écrite là arrive à l'agent telle quelle. Seule la valeur d'une variable d'environnement est substituée. On l'a appris à nos dépens : une référence citée dans la description d'un ticket ressortait résolue dans le premier message de l'agent lancé depuis ce ticket.
Une clé est déjà passée dans une conversation. Je fais quoi ?
Vous la changez d'abord, avant toute autre chose, parce qu'un prompt ne se reprend pas : il est chez le fournisseur et dans le fichier de transcript sur votre disque. Ensuite vous supprimez ou tronquez les transcripts qui la contiennent, vous vérifiez votre gestionnaire de presse-papiers, et vous cherchez dans le dépôt au cas où l'agent l'aurait écrite dans un fichier. Et seulement après, vous mettez la nouvelle valeur derrière une variable d'environnement.
En bref
Un agent n'a pas besoin de lire votre clé. Il a besoin d'un process dont l'environnement la contient déjà.
Enregistrez la valeur une fois, hors du dépôt, chiffrée par le système. Référencez-la par son nom là où l'environnement est construit. Laissez l'agent écrire $NOM. Gardez tous les autres canaux littéraux, y compris ceux où la substitution aurait été pratique, parce que les canaux pratiques sont précisément ceux qui se stockent et se transmettent.
Et quand vous vous tromperez, ce qui arrivera, changez la clé d'abord et rangez ensuite.
Télécharger AgentsRoom
Lancez tous vos agents IA, sur tous vos projets, depuis une seule fenêtre.
App companion : suivez vos agents en déplacement
Utilisez Claude, Codex, Antigravity CLI ou un autre fournisseur IA.
Remontez bugs et demandes directement dans votre backlog public.
Continuer la lecture
Sept agents IA font tourner nos nuits : des agents planifiés au-delà du code, avec les prompts
Un utilisateur nous a demandé comment on utilise des agents IA pour autre chose qu'écrire du code. Depuis le 28 août, sept agents planifiés démarrent chaque soir sur un Mac mini : un CEO de garde, une équipe SEO, un product manager, un correcteur de bugs, une équipe réseaux sociaux, un documentaliste et un rapporteur qui envoie un e-mail de 25 lignes. 33 nuits, 31 e-mails du matin, 51 bugs corrigés avec le lien du commit, 7 articles de blog en 20 langues. Ce que fait chacun, comment ils se passent le travail sans se parler, quel modèle fait quel métier, les quatre règles que leurs prompts ont dû apprendre, et les prompts eux-mêmes, prêts à copier.
Lire l'articleFan out de subagents dans Claude Code, puis vérifier ce qui revient
Dans Claude Code, faire un fan out, c'est découper un travail en tranches indépendantes et confier chacune à un subagent : en le demandant, avec /batch, ou avec une boucle claude -p. Vérifié sur Claude Code 2.1.301. Et comment on contrôle la fusion des six subagents qui traduisent notre blog chaque nuit.
Lire l'articleUn compte Claude sur deux ordinateurs, ou à deux : ce qui marche
Un compte Claude se connecte sur tous tes appareils, et tous puisent dans les mêmes limites de 5 heures et de la semaine, Claude et Claude Code ensemble. À deux sur un compte, c'est contraire aux conditions d'Anthropic, et il n'existe pas d'offre famille. Ce qu'on a vérifié le 25 octobre 2026, et comment voir quel ordinateur a consommé quoi.
Lire l'article