Como dar um segredo a um agente de código sem nunca colocá-lo no prompt
Um agente precisa de uma chave da Stripe ou de uma senha de banco de dados para rodar o comando dele. Você cola no chat e ela vai parar na transcrição no seu disco, no provedor do modelo e às vezes em um commit. A regra a que chegamos depois de três erros nossos: um segredo chega a um agente por uma variável de ambiente e por mais nada.
A situação é sempre a mesma. Um agente está no meio de uma tarefa e precisa chamar sua API de testes da Stripe, rodar uma migração no banco de staging ou publicar em um registro privado. Ele pede a chave. Você tem a chave no seu gerenciador de senhas, o agente está esperando, e a coisa mais rápida do mundo é colar no chat.
Essa colagem é o momento em que a chave sai do seu controle. Não porque o modelo seja malicioso, mas porque um prompt é um objeto armazenado e encaminhado: ele vai para um arquivo de transcrição no seu disco, vai para o provedor do modelo, e é copiado por cada retentativa e cada subagente que herda a conversa.
Nós desenvolvemos o AgentsRoom, um aplicativo de desktop que roda agentes de código, então tivemos que resolver isso para nós mesmos. Erramos três vezes em setembro de 2026. Esta é a regra a que chegamos, os três erros que a produziram e como aplicá-la usando ou não o nosso aplicativo.
A resposta curta
- Um segredo chega a um agente por uma variável de ambiente, e por mais nada. Nem uma mensagem, nem um ticket, nem um skill, nem uma opção de linha de comando.
- O agente usa
$NAME, nunca o valor. O shell expande na hora em que o comando roda. - Guarde o valor uma única vez, fora do repositório, criptografado pelo chaveiro do seu sistema, e referencie pelo nome em todo o resto.
- Um segredo que passou por uma conversa está queimado. Rotacione e depois faça a limpeza.
- O mascaramento é uma rede de segurança, não um plano. Ele pega o que parece uma chave, não uma senha de banco de dados que se lê como uma palavra.
Por que essa colagem é pior do que parece
Três coisas acontecem ao mesmo tempo, e só a primeira é óbvia.
Vai para o provedor do modelo. Essa é a parte que todo mundo vê. Sua chave agora está no corpo de uma requisição, na infraestrutura de outra pessoa, dentro de uma conversa que você não pode editar.
Vai para o seu disco, em texto puro. O Claude Code, o Codex, o Antigravity CLI e os demais guardam uma transcrição da conversa para que você possa retomá-la. Esse arquivo fica na sua pasta pessoal, sem criptografia, enquanto o CLI mantiver o histórico. Procure uma vez a string sk- nas suas transcrições e veja o que aparece.
Ela se espalha pelos lados. A conversa é a memória do agente, então tudo que copia a conversa copia a chave: uma sessão retomada, um agente criado por fork, um subagente lançado com o contexto do pai, um resumo escrito em um arquivo do projeto. Já vimos uma chave viajar de uma mensagem de chat para a descrição de um ticket e daí para a primeira mensagem de um segundo agente, sem ninguém fazer nada de errado.
E a rede de segurança de sempre não segura. O mascaramento da saída trabalha por padrão: sk-…, glpat-…, o formato de um JWT. Ele não tem como saber que thursday-harbour-71 é a senha do seu banco de staging. No nosso próprio aplicativo nós mascaramos os valores reconhecidos na saída dos terminais e mesmo assim tratamos isso como uma rede embaixo do trapézio, não como o trapézio.
A regra da porta única
Aqui está ela, em uma linha: uma credencial chega a um agente por uma variável de ambiente do processo em que ele roda, e por nenhum outro canal.
Todo o resto é texto literal. Uma mensagem que você digita, a descrição de um ticket, um arquivo de skill, um prompt de sistema, uma opção de linha de comando: tudo isso é lido por um humano ou por um modelo, então um segredo escrito ali é um segredo publicado.
A linha de comando merece a própria frase, porque ela parece mais segura que uma mensagem de chat e não é. Um valor em --api-key=… é visível para todos os processos da máquina através do ps, cai no histórico do seu shell, é registrado por qualquer coisa que guarde o comando lançado, e reaparece nas ferramentas de diagnóstico que exibem de volta a linha do processo. Uma variável de ambiente de um processo é legível por esse processo e pelo root. Superfície menor, a mesma comodidade.
O agente, por sua vez, nunca precisa do valor. Ele precisa escrever isto:
curl -H "Authorization: Bearer $STRIPE_SECRET_KEY" https://api.stripe.com/v1/charges
O shell expande $STRIPE_SECRET_KEY na execução. O agente escreveu dezessete caracteres e um cifrão. A transcrição dele contém dezessete caracteres e um cifrão.
Como isso funciona no nosso aplicativo
O mecanismo importa menos que o formato, mas o formato é mais fácil de copiar quando se vê uma implementação.
Um cofre, um arquivo. O AgentsRoom guarda os segredos em um único arquivo na sua pasta pessoal, em modo 0600, criptografado pelo chaveiro do sistema operacional, reafirmado a cada escrita. Nada é sincronizado com um servidor e nada passa para outro computador: um segredo pertence à máquina que o guarda. Se o chaveiro estiver indisponível, salvar falha em vez de cair para texto puro.
Você salva um valor uma única vez. Comandos e ligações > Segredos, em qualquer projeto. Um nome (letras, dígitos, ponto, hífen, sublinhado, 64 caracteres, para que sirva como nome de variável de ambiente) e um valor, digitado em um campo de senha. A linha que aparece mostra o nome e a referência dele, {{secret:STRIPE_SECRET_KEY}}, e um botão que copia a referência. Não existe botão de revelar nem botão de copiar o valor, porque não existe nenhum caminho de código que devolva um valor para a interface.
Você referencia onde o ambiente é construído. Editar agente > Avançado > Variáveis de ambiente, ou as configurações do projeto, ou as do provedor, ou uma linha de comando de dev:
STRIPE_SECRET_KEY={{secret:STRIPE_SECRET_KEY}}
Na inicialização, o processo principal substitui o valor no ambiente do terminal que ele está prestes a criar. A interface nunca vê, o agente nunca vê, o celular nunca vê. A página Gerenciador de segredos percorre as telas.
O agente descobre nomes, não valores. Um agente conectado às nossas ferramentas MCP pode chamar secrets_list e receber a lista de nomes presentes naquela máquina. Isso já basta para ele ser útil: ele pode dizer “você tem um STRIPE_SECRET_KEY salvo, adicione STRIPE_SECRET_KEY={{secret:STRIPE_SECRET_KEY}} ao ambiente deste agente e eu vou usar $STRIPE_SECRET_KEY”. Ele não consegue ler o valor, nem mesmo enquanto roda um comando que o usa.
Três erros que nós publicamos
A regra acima parece óbvia depois de escrita. Ela é a cicatriz de três bugs, todos em setembro de 2026, todos reportados por usuários.
Uma referência citada em um ticket saía resolvida
19 de setembro. Robert documentou um mapeamento na descrição de um ticket, o perfeitamente razoável STRIPE_SECRET_KEY={{secret:STRIPE_SECRET_KEY}}, para que quem pegasse o ticket soubesse o que configurar. Lido pela API, o ticket devolvia a referência intacta. Mas o agente lançado a partir daquele ticket recebia o valor na primeira mensagem.
A causa era um detalhe de encanamento com uma consequência real. O briefing de um ticket vira o primeiro prompt do agente, que viajava dentro de uma variável de ambiente do comando de lançamento. Nosso resolvedor substituía todos os valores de ambiente, então substituía o prompt também. A chave foi para o disco e para o provedor do modelo. Rotação obrigatória, sem saída.
A correção foi tornar literal o comando de lançamento do agente: quando o ambiente carrega um identificador de agente, a variável que contém o primeiro prompt fica intocada. Um comando de dev que usa a mesma variável não tem identificador de agente e resolve como antes. Aceitamos um efeito colateral de propósito: uma referência digitada nas opções de CLI de um agente também não é resolvida, o que está correto, já que uma linha de comando acaba no ps e nos logs de qualquer forma.
A lição: a porta precisa ser estreita de propósito. “Substituir em todo lugar onde pudesse ser útil” é exatamente como um segredo acaba onde nunca deveria estar.
Uma referência colada em uma mensagem, que nunca resolve
22 de setembro. Cs040618 reportou o problema oposto: “eu colo a referência na conversa e o agente não consegue entender o que é essa chave”.
Não é um bug. Uma mensagem é texto literal por projeto, que é exatamente a correção de três dias antes. Mas nada no aplicativo dizia isso no momento do gesto, e o agente, recebendo {{secret:…}} em uma mensagem, não fazia ideia do que responder.
Três correções, todas sobre dizer onde fica a porta: uma dica que aparece quando você cola uma referência no campo de redação e aponta para as variáveis de ambiente, um texto de ajuda acima da lista de segredos que nomeia os três campos onde uma referência é substituída e diz “nunca em uma mensagem”, e uma linha nas próprias instruções do agente dizendo o que responder quando uma referência chega em uma mensagem.
“Configurações > Segredos” não existia
28 de setembro. O agente do Mohammad abriu um relato: o usuário diz que adicionou OTPIQ_API_KEY em Configurações > Segredos, que salvou várias vezes ao longo de trinta minutos, e secrets_list continua devolvendo os mesmos três segredos antigos.
O caminho de salvamento estava certo. O segredo nunca tinha chegado ao cofre, porque não existe página Segredos nas configurações. Seis textos de ajuda do aplicativo de desktop, uma página deste site e as próprias instruções do agente mandavam as pessoas para uma tela que não existia. O que existe mesmo nas configurações é o bloco de variáveis de ambiente, então foi ali que ele digitou o token, entre chaves, o que não é uma referência: nunca substituído, enviado ao agente como está, e sincronizado com o projeto, então o token saiu da máquina.
Corrigimos os textos para que nomeiem o caminho real, fizemos as ferramentas voltadas aos agentes dizerem onde um segredo é adicionado, e acrescentamos uma verificação no bloco de ambiente que sinaliza uma credencial digitada em claro, um nome entre chaves que não é uma referência, e uma referência a um segredo que não existe nesta máquina.
A lição aqui não tem nada a ver com segredos: um caminho errado em um texto de ajuda é um bug de segurança. Ele leva o usuário para o campo mais próximo que parece ser o certo.
Se você não usa o AgentsRoom
A regra viaja. Escolha a opção que encaixa na sua instalação; todas terminam no mesmo lugar, uma variável de ambiente no processo em que o agente roda.
- O CLI de um gerenciador de senhas.
op run -- claudecom o 1Password, ou o equivalente no Bitwarden e no Doppler: a ferramenta lê referências de um modelo, injeta os valores reais no ambiente do processo filho, e nada é escrito no disco. direnvcom um.envrcno gitignore. Simples, local, por pasta. Adicione.envrce.env*ao.gitignoreantes do primeiro valor, não depois.- Um arquivo
.envque o agente nunca lê. Mantenha fora do repositório e carregue no shell que lança o agente. Se o arquivo estiver dentro do repositório, o agente vai acabar abrindo, citando em uma mensagem, e você volta ao ponto de partida. - Credenciais de nuvem: use as de curta duração. GitHub OIDC no CI em vez de chaves AWS de longa duração, e uma identidade de carga de trabalho em vez de um arquivo de chave de conta de serviço.
Seja qual for a escolha, coloque a regra nas instruções do agente, para ele parar de pedir. Um parágrafo em CLAUDE.md ou AGENTS.md resolve: nunca pedir o valor de uma credencial, nunca escrever uma em um arquivo, usar $NAME e dizer ao usuário qual variável configurar. Publicamos um pequeno skill que diz exatamente isso, e ele tem cinco linhas.
Se uma chave já passou por uma conversa
Nesta ordem, e o primeiro passo não é opcional.
- Rotacione. Um prompt não dá para desenviar. Considere o valor comprometido e emita um novo.
- Encontre as transcrições. Os CLIs guardam os arquivos de conversa na sua pasta pessoal. Procure neles o valor antigo e apague ou trunque o que corresponder.
- Verifique os lugares que copiam texto. O histórico do gerenciador de área de transferência, o ticket ou a issue em que o agente foi briefado, qualquer resumo que o agente tenha escrito no repositório, e
git log -pse o agente commitou enquanto a segurava. - E só então monte a porta. Novo valor atrás de uma variável de ambiente, referência pelo nome, e instruções do agente atualizadas para que o próximo não peça.
O passo 4 por último, porque um mecanismo limpo em volta de uma chave vazada é só um vazamento mais bem arrumado.
As perguntas que as pessoas realmente fazem
Por que uma chave de API nunca deve ir em um prompt para um agente de IA?
Porque um prompt é armazenado e encaminhado. O Claude Code, o Codex e os outros CLIs escrevem a conversa em um arquivo de transcrição no seu disco, e a própria mensagem vai para o provedor do modelo. A partir daí, a chave também está no histórico da sua área de transferência, em qualquer log que repita a mensagem, e nas retentativas e subagentes que copiam a conversa. O mascaramento por padrão pega coisas com formato de sk- ou glpat-, não uma senha de banco de dados que parece uma palavra comum.
Como um agente de código usa um segredo que ele não consegue ler?
Por uma variável de ambiente. Você coloca o valor em uma variável de ambiente do processo em que o agente roda, e o agente escreve $STRIPE_SECRET_KEY no comando em vez do valor. O shell expande na hora em que o comando roda. O agente nunca vê os caracteres, então eles nunca entram na conversa dele nem na transcrição.
Posso passar o segredo como argumento de linha de comando em vez disso?
Pode, e não deveria. Uma linha de comando é visível para todos os processos da máquina através do ps, entra no histórico do shell, nos logs de processo, e em qualquer ferramenta de diagnóstico que releia o comando que foi lançado. Uma variável de ambiente de um único processo é legível por esse processo e pelo root, o que é uma superfície bem menor.
Onde o AgentsRoom guarda os segredos que os agentes usam?
Em um único arquivo na sua pasta pessoal, em modo 0600, criptografado pelo chaveiro do seu sistema operacional, somente naquela máquina. Nada é sincronizado com um servidor, e não existe botão para exibir um valor de novo. O aplicativo mostra nomes, o agente vê nomes, e o valor só é descriptografado no processo principal, no momento em que um terminal ou um comando é iniciado.
O que acontece se eu colar uma referência de segredo em uma mensagem para o agente?
Nada é substituído, e isso é proposital. Uma mensagem, a descrição de um ticket, um skill e um prompt de sistema são texto literal, então uma referência escrita ali chega ao agente como texto. Só o valor de uma variável de ambiente é substituído. Aprendemos isso do jeito difícil: uma referência citada na descrição de um ticket saía resolvida na primeira mensagem do agente lançado a partir dele.
Uma chave já passou por uma conversa. O que eu faço?
Rotacione primeiro, antes de qualquer outra coisa, porque um prompt não dá para desenviar: ele está do lado do provedor e no arquivo de transcrição no seu disco. Depois apague ou trunque as transcrições que a contêm, verifique seu gerenciador de área de transferência, e procure no repositório caso o agente a tenha escrito em um arquivo. E só então coloque o novo valor atrás de uma variável de ambiente.
Em resumo
Um agente não precisa ler a sua chave. Ele precisa de um processo cujo ambiente já a contenha.
Salve o valor uma única vez, fora do repositório, criptografado pelo sistema. Referencie pelo nome onde o ambiente é construído. Deixe o agente escrever $NAME. Mantenha literais todos os outros canais, inclusive aqueles em que a substituição teria sido prática, porque os canais práticos são justamente os que são armazenados e encaminhados.
E quando você errar, e vai errar, rotacione a chave primeiro e arrume depois.
Baixar AgentsRoom
Rode todos os seus agentes de IA, em todos os seus projetos, de uma única janela.
App complementar: acompanhe seus agentes em qualquer lugar
Use Claude, Codex, Antigravity CLI ou outro provedor de IA.
Envie bugs e pedidos direto para o seu backlog público.
Continue lendo
Sete agentes de IA tocam as nossas noites: agentes agendados além do código, com os prompts
Um usuário nos perguntou como usamos agentes de IA para outra coisa além de escrever código. Desde 28 de agosto, sete agentes agendados começam toda noite em um Mac mini: um CEO de plantão, uma equipe de SEO, um product manager, um corretor de bugs, uma equipe de redes sociais, um documentalista e um relator que envia um e-mail de 25 linhas. 33 noites, 31 e-mails matinais, 51 bugs corrigidos com o link do commit, 7 artigos de blog em 20 idiomas. O que cada um faz, como eles passam o trabalho entre si sem conversar, qual modelo faz qual função, as quatro regras que os prompts tiveram de aprender, e os próprios prompts, prontos para copiar.
Leia o artigoManter o Claude Code rodando após uma queda do SSH: a receita com tmux
Mantenha o Claude Code ativo após uma queda do SSH com tmux. Volte ao mesmo processo, confira a persistência e use a opção opcional do AgentsRoom.
Leia o artigoUma conta do Claude em dois computadores, ou para duas pessoas: o que funciona
Uma conta do Claude pode ficar logada em todos os seus dispositivos, e todos consomem os mesmos limites de 5 horas e semanal, Claude e Claude Code juntos. Duas pessoas numa conta vai contra os termos da Anthropic, e não existe plano familiar. O que verificamos em 25 de outubro de 2026, e como ver qual computador gastou o quê.
Leia o artigo