Come dare un segreto a un agente di codice senza metterlo mai nel prompt

Un agente ha bisogno di una chiave Stripe o di una password di database per lanciare il suo comando. La incolli nella chat e finisce nella trascrizione sul tuo disco, dal fornitore del modello e a volte in un commit. La regola a cui siamo arrivati dopo tre errori nostri: un segreto raggiunge un agente tramite una variabile d'ambiente e nient'altro.

La situazione è sempre la stessa. Un agente è a metà di un'attività e deve chiamare la tua API Stripe di test, lanciare una migrazione sul database di staging o pubblicare su un registro privato. Chiede la chiave. Hai la chiave nel tuo gestore di password, l'agente aspetta, e la cosa più veloce del mondo è incollarla nella chat.

Quell'incollaggio è il momento in cui la chiave esce dal tuo controllo. Non perché il modello sia malevolo, ma perché un prompt è un oggetto memorizzato e inoltrato: finisce in un file di trascrizione sul tuo disco, parte verso il fornitore del modello, e viene ricopiato da ogni tentativo ripetuto e da ogni subagente che eredita la conversazione.

Sviluppiamo AgentsRoom, un'app desktop che fa girare agenti di codice, quindi abbiamo dovuto risolvere la cosa per noi stessi. Abbiamo sbagliato tre volte a settembre 2026. Ecco la regola a cui siamo arrivati, i tre errori che l'hanno prodotta e come applicarla, che tu usi o no la nostra app.

La risposta breve

  • Un segreto raggiunge un agente tramite una variabile d'ambiente, e nient'altro. Non un messaggio, non un ticket, non uno skill, non un'opzione della riga di comando.
  • L'agente usa $NAME, mai il valore. La shell la espande quando il comando viene eseguito.
  • Conserva il valore una volta sola, fuori dal repository, cifrato dal portachiavi del tuo sistema, e richiamalo per nome ovunque altro.
  • Un segreto passato in una conversazione è bruciato. Ruotalo, poi fai pulizia.
  • Il mascheramento è una rete di sicurezza, non un piano. Intercetta ciò che sembra una chiave, non una password di database che si legge come una parola.

Perché quell'incollaggio è peggio di come sembra

Succedono tre cose insieme, e solo la prima è evidente.

Parte verso il fornitore del modello. È la parte che vedono tutti. La tua chiave è ora nel corpo di una richiesta, sull'infrastruttura di qualcun altro, dentro una conversazione che non puoi modificare.

Finisce sul tuo disco, in chiaro. Claude Code, Codex, Antigravity CLI e gli altri tengono una trascrizione della conversazione per poterla riprendere. Quel file sta nella tua cartella personale, non cifrato, finché la CLI conserva la sua cronologia. Cerca una volta la stringa sk- nelle tue trascrizioni e guarda cosa esce.

Si propaga di lato. La conversazione è la memoria dell'agente, quindi tutto ciò che copia la conversazione copia la chiave: una sessione ripresa, un agente forkato, un subagente lanciato con il contesto del genitore, un riassunto scritto in un file del progetto. Abbiamo visto una chiave viaggiare da un messaggio di chat alla descrizione di un ticket e da lì al primo messaggio di un secondo agente, senza che nessuno facesse nulla di sbagliato.

E la solita rete di sicurezza non tiene. Il mascheramento dell'output lavora per pattern: sk-…, glpat-…, la forma di un JWT. Non può sapere che thursday-harbour-71 è la password del tuo database di staging. Nella nostra app mascheriamo i valori riconosciuti nell'output dei terminali e lo consideriamo comunque una rete sotto il trapezio, non il trapezio.

La regola della porta unica

Eccola, in una riga: una credenziale raggiunge un agente tramite una variabile d'ambiente del processo in cui gira, e tramite nessun altro canale.

Tutto il resto è testo letterale. Un messaggio che scrivi, la descrizione di un ticket, un file di skill, un prompt di sistema, un'opzione della riga di comando: tutto questo viene letto da un umano o da un modello, quindi un segreto scritto lì è un segreto pubblicato.

La riga di comando merita una frase a parte, perché sembra più sicura di un messaggio di chat e non lo è. Un valore in --api-key=… è visibile a tutti i processi della macchina tramite ps, atterra nella cronologia della tua shell, viene registrato da qualunque cosa salvi il comando lanciato, e ricompare negli strumenti diagnostici che ti rimostrano la riga del processo. Una variabile d'ambiente di un processo è leggibile da quel processo e da root. Superficie più piccola, stessa comodità.

L'agente, dal canto suo, non ha mai bisogno del valore. Ha bisogno di scrivere questo:

curl -H "Authorization: Bearer $STRIPE_SECRET_KEY" https://api.stripe.com/v1/charges

La shell espande $STRIPE_SECRET_KEY all'esecuzione. L'agente ha scritto diciassette caratteri e un simbolo del dollaro. La sua trascrizione contiene diciassette caratteri e un simbolo del dollaro.

Come funziona nella nostra app

Il meccanismo conta meno della forma, ma la forma è più facile da copiare quando se ne vede un'implementazione.

Una cassaforte, un file. AgentsRoom tiene i segreti in un unico file nella tua cartella personale, in modalità 0600, cifrato tramite il portachiavi del sistema operativo, riaffermato a ogni scrittura. Nulla viene sincronizzato su un server e nulla passa su un altro computer: un segreto appartiene alla macchina che lo detiene. Se il portachiavi non è disponibile, il salvataggio fallisce invece di ripiegare sul testo in chiaro.

Salvi un valore una volta sola. Comandi e connessioni > Segreti, in qualsiasi progetto. Un nome (lettere, cifre, punto, trattino, trattino basso, 64 caratteri, così è utilizzabile tale e quale come nome di variabile d'ambiente) e un valore, digitato in un campo password. La riga che compare mostra il nome e il suo riferimento, {{secret:STRIPE_SECRET_KEY}}, e un pulsante che copia il riferimento. Non c'è un pulsante per rivelare né uno per copiare il valore, perché non esiste alcun percorso di codice che restituisca un valore all'interfaccia.

Lo richiami dove l'ambiente viene costruito. Modifica agente > Avanzate > Variabili d'ambiente, oppure le impostazioni del progetto, o quelle del provider, o una riga di comando di sviluppo:

STRIPE_SECRET_KEY={{secret:STRIPE_SECRET_KEY}}

All'avvio, il processo principale sostituisce il valore nell'ambiente del terminale che sta per creare. L'interfaccia non lo vede mai, l'agente non lo vede mai, il telefono non lo vede mai. La pagina Gestore di segreti mostra le schermate.

L'agente scopre i nomi, non i valori. Un agente collegato ai nostri strumenti MCP può chiamare secrets_list e ricevere l'elenco dei nomi presenti su quella macchina. Tanto gli basta per essere utile: può dire «hai un STRIPE_SECRET_KEY salvato, aggiungi STRIPE_SECRET_KEY={{secret:STRIPE_SECRET_KEY}} all'ambiente di questo agente e userò $STRIPE_SECRET_KEY». Non può leggere il valore, nemmeno mentre esegue un comando che lo usa.

Tre errori che abbiamo rilasciato

La regola qui sopra sembra ovvia una volta scritta. È la cicatrice di tre bug, tutti a settembre 2026, tutti segnalati da utenti.

Un riferimento citato in un ticket usciva risolto

19 settembre. Robert aveva documentato una mappatura nella descrizione di un ticket, il perfettamente ragionevole STRIPE_SECRET_KEY={{secret:STRIPE_SECRET_KEY}}, perché chi avesse preso il ticket sapesse cosa impostare. Riletto dall'API, il ticket restituiva il riferimento intatto. Ma l'agente lanciato da quel ticket riceveva il valore nel suo primo messaggio.

La causa era un dettaglio di idraulica con una conseguenza reale. Il brief di un ticket diventa il primo prompt dell'agente, che viaggiava dentro una variabile d'ambiente del comando di lancio. Il nostro risolutore sostituiva tutti i valori d'ambiente, quindi sostituiva anche il prompt. La chiave è finita sul disco e dal fornitore del modello. Rotazione obbligatoria, nessun modo di evitarla.

La correzione è stata rendere letterale il comando di lancio di un agente: quando l'ambiente porta un identificatore di agente, la variabile che contiene il primo prompt non viene toccata. Un comando di sviluppo che usa la stessa variabile non ha un identificatore di agente e si risolve come prima. Abbiamo accettato un effetto collaterale di proposito: un riferimento scritto nelle opzioni CLI di un agente non si risolve più nemmeno lui, il che è corretto, visto che una riga di comando finisce comunque in ps e nei log.

La lezione: la porta deve essere stretta di proposito. «Sostituire ovunque possa servire» è esattamente il modo in cui un segreto finisce dove non dovrebbe mai stare.

Un riferimento incollato in un messaggio, che non si risolve mai

22 settembre. Cs040618 ha segnalato il problema opposto: «incollo il riferimento nella conversazione e l'agente non riesce a capire cosa sia questa chiave».

Non è un bug. Un messaggio è testo letterale per scelta progettuale, che è esattamente la correzione di tre giorni prima. Ma nulla nell'app lo diceva al momento del gesto, e l'agente, ricevendo {{secret:…}} in un messaggio, non aveva idea di cosa rispondere.

Tre correzioni, tutte per dire dov'è la porta: un suggerimento che scatta quando incolli un riferimento nel campo di scrittura e indica le variabili d'ambiente, un testo di aiuto sopra l'elenco dei segreti che nomina i tre campi in cui un riferimento viene sostituito e dice «mai in un messaggio», e una riga nelle istruzioni dell'agente stesso che gli dice cosa rispondere quando gli arriva un riferimento in un messaggio.

«Impostazioni > Segreti» non esisteva

28 settembre. L'agente di Mohammad ha depositato una segnalazione: l'utente dice di aver aggiunto OTPIQ_API_KEY in Impostazioni > Segreti, di averlo salvato più volte nell'arco di trenta minuti, e secrets_list restituisce sempre gli stessi tre vecchi segreti.

Il percorso di salvataggio andava bene. Il segreto non era mai arrivato nella cassaforte, perché non esiste una pagina Segreti nelle impostazioni. Sei testi di aiuto dell'app desktop, una pagina di questo sito e le istruzioni dell'agente mandavano tutti verso una schermata che non esisteva. Quello che esiste davvero nelle impostazioni è il blocco delle variabili d'ambiente: è lì quindi che ha digitato il token, tra graffe, il che non è un riferimento. Mai sostituito, inviato all'agente così com'è, e sincronizzato con il progetto: il token ha lasciato la macchina.

Abbiamo corretto i testi perché nominino il percorso vero, fatto dire agli strumenti destinati agli agenti dove si aggiunge un segreto, e aggiunto un controllo sul blocco d'ambiente che segnala una credenziale digitata in chiaro, un nome tra graffe che non è un riferimento, e un riferimento a un segreto assente da questa macchina.

La lezione qui non c'entra nulla con i segreti: un percorso sbagliato in un testo di aiuto è un bug di sicurezza. Manda l'utente verso il campo più vicino che sembra quello giusto.

Se non usi AgentsRoom

La regola viaggia. Prendi fra queste opzioni quella che corrisponde alla tua installazione; arrivano tutte allo stesso punto, una variabile d'ambiente nel processo in cui gira l'agente.

  • La CLI di un gestore di password. op run -- claude con 1Password, o l'equivalente in Bitwarden e Doppler: lo strumento legge i riferimenti da un modello, inietta i valori reali nell'ambiente del processo figlio, e nulla viene scritto sul disco.
  • direnv con un .envrc nel gitignore. Semplice, locale, per cartella. Aggiungi .envrc e .env* al .gitignore prima del primo valore, non dopo.
  • Un file .env che l'agente non legge mai. Tienilo fuori dal repository e caricalo nella shell che lancia l'agente. Se il file è dentro il repository, l'agente finirà per aprirlo, citarlo in un messaggio, ed eccoti tornato al punto di partenza.
  • Credenziali cloud: prendile di breve durata. GitHub OIDC nella CI invece di chiavi AWS a lunga durata, e un'identità di carico di lavoro invece di un file di chiave di account di servizio.

Qualunque cosa tu scelga, metti la regola nelle istruzioni dell'agente, così smette di chiedere. Basta un paragrafo in CLAUDE.md o AGENTS.md: non chiedere mai il valore di una credenziale, non scriverne mai una in un file, usare $NAME e dire all'utente quale variabile impostare. Pubblichiamo un piccolo skill che dice esattamente questo, ed è lungo cinque righe.

Se una chiave è già passata in una conversazione

In quest'ordine, e il primo passo non è facoltativo.

  1. Ruotala. Un prompt non si può ritirare. Considera il valore compromesso ed emettine uno nuovo.
  2. Ritrova le trascrizioni. Le CLI tengono i file di conversazione nella tua cartella personale. Cercaci dentro il vecchio valore e cancella o tronca ciò che corrisponde.
  3. Controlla i posti che copiano testo. La cronologia del gestore degli appunti, il ticket o la issue in cui l'agente è stato istruito, qualunque riassunto che l'agente abbia scritto nel repository, e git log -p se l'agente ha committato mentre la deteneva.
  4. E solo allora monta la porta. Nuovo valore dietro una variabile d'ambiente, riferimento per nome, e istruzioni dell'agente aggiornate perché il prossimo non chieda.

Il passo 4 per ultimo, perché un meccanismo pulito attorno a una chiave trapelata è solo una fuga messa in ordine meglio.

Le domande che le persone fanno davvero

Perché una chiave API non deve mai finire in un prompt rivolto a un agente IA?

Perché un prompt viene memorizzato e inoltrato. Claude Code, Codex e le altre CLI scrivono la conversazione in un file di trascrizione sul tuo disco, e il messaggio stesso parte verso il fornitore del modello. Da lì la chiave è anche nella cronologia degli appunti, in qualunque log che ricopi il messaggio, e nei tentativi ripetuti e nei subagenti che copiano la conversazione. Il mascheramento per pattern intercetta ciò che ha la forma di sk- o glpat-, non una password di database che sembra una parola qualsiasi.

Come fa un agente di codice a usare un segreto che non può leggere?

Tramite una variabile d'ambiente. Metti il valore in una variabile d'ambiente del processo in cui gira l'agente, e l'agente scrive $STRIPE_SECRET_KEY nel comando al posto del valore. La shell la espande quando il comando viene eseguito. L'agente non vede mai i caratteri, quindi non entrano mai nella sua conversazione né nella sua trascrizione.

Posso passare il segreto come argomento della riga di comando?

Puoi, ma non dovresti. Una riga di comando è visibile a tutti i processi della macchina tramite ps, finisce nella cronologia della shell, nei log dei processi, e in qualunque strumento diagnostico che rilegga il comando lanciato. Una variabile d'ambiente di un singolo processo è leggibile da quel processo e da root, che è una superficie molto più piccola.

Dove conserva AgentsRoom i segreti che gli agenti usano?

In un unico file nella tua cartella personale, in modalità 0600, cifrato tramite il portachiavi del tuo sistema operativo, solo su quella macchina. Nulla viene sincronizzato su un server, e non esiste alcun pulsante per rivedere un valore. L'app mostra i nomi, l'agente vede i nomi, e il valore viene decifrato solo nel processo principale, nel momento in cui parte un terminale o un comando.

Cosa succede se incollo un riferimento a un segreto in un messaggio all'agente?

Non viene sostituito nulla, ed è voluto. Un messaggio, la descrizione di un ticket, uno skill e un prompt di sistema sono testo letterale, quindi un riferimento scritto lì arriva all'agente come testo. Viene sostituito solo il valore di una variabile d'ambiente. L'abbiamo imparato a nostre spese: un riferimento citato nella descrizione di un ticket usciva risolto nel primo messaggio dell'agente lanciato da quel ticket.

Una chiave è già passata in una conversazione. Cosa faccio?

Prima di tutto la ruoti, perché un prompt non si può ritirare: è dal lato del fornitore e nel file di trascrizione sul tuo disco. Poi cancelli o tronchi le trascrizioni che la contengono, controlli il gestore degli appunti, e cerchi nel repository nel caso in cui l'agente l'abbia scritta in un file. E solo dopo metti il nuovo valore dietro una variabile d'ambiente.

In breve

Un agente non ha bisogno di leggere la tua chiave. Ha bisogno di un processo il cui ambiente la contenga già.

Salva il valore una volta sola, fuori dal repository, cifrato dal sistema. Richiamalo per nome dove l'ambiente viene costruito. Lascia che l'agente scriva $NAME. Mantieni letterali tutti gli altri canali, compresi quelli in cui la sostituzione sarebbe stata comoda, perché i canali comodi sono proprio quelli che vengono memorizzati e inoltrati.

E quando sbaglierai, perché succederà, ruota prima la chiave e sistema dopo.

Scarica AgentsRoom

Esegui tutti i tuoi agenti AI, su tutti i tuoi progetti, da una sola finestra.

GratisScarica AgentsRoom

App companion: monitora i tuoi agenti in movimento

Usa Claude, Codex, Antigravity CLI o un altro provider IA.

Installa l'estensione
Chrome Web Store

Invia bug e richieste direttamente nel tuo backlog pubblico.

Multi-progetto
Multi-provider
Multi-agente
Stato in tempo reale
Diff e commit
App mobile
Anteprima live
Team di agenti
Test browser
Dev guidata da backlog
Libreria di prompt
Libreria di skill
Vedi tutte le funzionalità

Continua a leggere