O hook nunca chegou ao modelo
Em 31 de agosto, a Token Security detalhou no The Hacker News os novos endpoints da Compliance API da Anthropic para sessões locais do Claude Code. São uma melhoria real, e o texto é preciso sobre onde o transcript termina: hooks que disparam antes de uma ferramenta rodar, arquivos parados no disco, processos iniciados fora de uma sessão, qualquer coisa servida por Bedrock ou Vertex. O worm de npm da semana passada viveu a vida inteira nessa lacuna. O Bromure Agentic Coding coloca a escuta no fio entre a VM e todo o resto, então o registro cobre o que aconteceu e não o que alguém disse ao modelo.
Um transcript só pode conter aquilo que alguém disse ao modelo. A metade interessante de uma sessão de agente é a metade que ninguém diz em voz alta.
Durante quase todo este ano, um gerente de engenharia que quisesse saber o que o Claude Code andou fazendo em um notebook tinha duas opções: ler o scrollback do desenvolvedor, ou comprar um wrapper de terceiros. Os endpoints de conformidade da Anthropic cobriam o claude.ai e o Claude Desktop, e o Claude Code quase nada.
Isso mudou em 11 de agosto. A Anthropic entregou três endpoints da Compliance
API para sessões locais: um lista sessões, outro busca os metadados de uma
sessão, e o terceiro puxa o transcript completo de
GET /v1/compliance/apps/sessions/local/{session_id}/messages. Em 31 de agosto,
a Token Security publicou
um passeio pelo que eles entregam
no The Hacker News.
A Token Security patrocinou aquele texto, e ele continua sendo um dos relatos mais cuidadosos que já li sobre onde fica o horizonte de um log.
Três tipos de bloco, e o que eles cobrem
O transcript chega em três tipos de bloco. Nas palavras do artigo: “Tudo o que
é comunicado ao modelo é registrado em três tipos de bloco: text, tool_use e
tool_result. Entre eles, cobrem prompts do usuário, comandos bash, leituras e
escritas, e até comandos MCP.”
Isso é bastante: cada comando de shell que o modelo escolheu, cada arquivo que ele leu, cada ferramenta MCP que ele chamou. Se a sua pergunta é “o que este agente decidiu fazer na terça”, o transcript responde, e responde a partir dos servidores da Anthropic e não de um arquivo na máquina que você está investigando.
A oração que faz todo o trabalho é a primeira: tudo o que é comunicado ao modelo.
O horizonte
Quatro coisas ficam fora dessa fronteira, e o artigo nomeia todas as quatro.
Hooks. “Hooks são o caso mais claro: rodam localmente, entre a decisão do modelo e a ferramenta efetivamente rodar, e podem impedir que uma ferramenta execute ou que um prompt seja enviado.” Um hook é código no disco do desenvolvedor que dispara na fresta entre o modelo escolher uma ação e a ação acontecer. O modelo nunca fica sabendo, então o transcript nunca carrega aquilo.
Disco. “Nenhum dos dois enxerga o que está no disco: arquivos de configuração, skills e plugins instalados e seus arquivos .md (a menos que tenham sido usados em uma sessão), ou processos lançados fora de uma sessão.” Uma skill que você instala e nunca invoca não deixa rastro, e o mesmo vale para um processo em segundo plano que o agente iniciou uma hora atrás e esqueceu.
Outros provedores de modelo. “Se você roda o Claude Code em um modelo que não é da Anthropic, você não tem cobertura nenhuma da Compliance API, porque ela só registra interações com os modelos da Anthropic. Sessões rodando em Bedrock, Foundry ou Google Cloud não serão cobertas.” A cobertura para nos modelos da Anthropic, o que deixa de fora o Codex, o Gemini CLI, o Grok e o que quer que seu time instale no próximo trimestre.
Decisões de permissão. A aprovação de um comando perigoso por um desenvolvedor, ou uma flag de bypass que deixou um prompt inteiro passar, cai no OpenTelemetry e não no transcript de conformidade.
Tudo isso é comportamento correto. Um log ancorado no modelo registra o que o modelo viu. A pergunta para a sua próxima revisão de segurança é se as coisas que você mais precisa ver caem do lado do modelo dessa linha.
O worm da semana passada morava nessa lacuna
Quatro dias atrás, um gerador de código npm com mais de 150 mil downloads semanais começou a distribuir um ladrão de credenciais. Nós descrevemos a cadeia de publicação no sábado: um estranho comentou em um pull request, o workflow de release do projeto leu o comentário sem checar quem o escreveu, e dez versões assinadas saíram.
Releia aquele malware com o transcript de conformidade na outra mão. Trace onde cada passo apareceria.
O agente roda npm install. Isso é um bloco tool_use, e o transcript tem. Tudo
depois disso é processo filho.
A primeira onda não declarava script de instalação nenhum. Seu payload ficava no
binding.gyp, a descrição de build que o node-gyp lê, dentro de um campo
conditions que o node-gyp avalia com Python. O modelo nunca teve um turno
sobre aquilo e nenhuma chamada de ferramenta o nomeia: uma expressão Python em um
arquivo de build, rodando como neta do único comando que o transcript registrou
como perfeitamente comum.
A varredura que veio em seguida percorreu mais de 150 padrões glob pelo diretório
home atrás de chaves SSH, arquivos .env, credenciais de nuvem e tokens de
registry. Ninguém perguntou nada disso ao modelo.
Depois a persistência. Em cada repositório que conseguia alcançar, o worm
escrevia um .claude/settings.json carregando um hook SessionStart que roda o
setup.mjs toda vez que um desenvolvedor abre o projeto no Claude Code. Um hook,
no disco, disparando antes de alguém consultar o modelo: dois dos quatro pontos
cegos em um único arquivo. O atacante que escolheu aquele lugar quase certamente
nunca leu o changelog de conformidade de fornecedor nenhum.
A janela hostil inteira durou três horas e onze minutos, e parte alguma dela chegou a um modelo.
Onde o Bromure coloca a escuta
O Bromure Agentic Coding roda cada workspace como sua própria máquina virtual em Apple Silicon, e tudo o que sai dessa VM passa por um proxy e um switch virtual que vivem do lado Mac do hipervisor. O switch desvia os fluxos das portas 80 e 443 da VM para o proxy sem nenhuma variável de ambiente a configurar e sem nada que o convidado possa desligar, então o registro não depende da cooperação do agente, nem de o agente saber que o proxy está ali.
No nível de trace Somente atividade e acima, cada requisição ganha um
registro de metadados: carimbo de tempo, host, porta, método, caminho, código de
status, latência, bytes de requisição medidos antes de qualquer troca de
credencial, bytes de resposta, quais credenciais o proxy substituiu na saída, e
um aviso se a requisição carregava um bearer token que o Bromure não emitiu. Esse
registro existe quer a requisição venha do agente, de um script postinstall, de
um servidor MCP fazendo suas próprias coisas, ou de um processo que alguém
iniciou três horas atrás e esqueceu.
A janela Linha do tempo de segurança (Window → Security Timeline…) fica ao
lado e responde a outra pergunta. O Trace Inspector diz o que o agente enviou; a
linha do tempo diz o que os motores do Bromure decidiram. Uma tabela cronológica,
a mais recente primeiro, com cores: verde para permitido, vermelho para
bloqueado, azul para informativo — Corretagem de credenciais, Firewall, Cadeia de
suprimentos, Guardrails, Injeção de prompt, Credencial usada, TLS upstream. Ela
guarda 5.000 linhas em memória. A cópia durável são os traces de sessão
criptografados em ~/Library/Application Support/BromureAC/traces/, selados com
AES-GCM pela mesma chave do Keychain que guarda os segredos do seu workspace.
A mesma instalação, em um workspace Bromure, se lê assim.
Nenhuma dessas linhas exige que o payload tenha passado por um modelo, e nenhuma delas pode ser editada por código dentro da VM, porque os motores que as escrevem rodam no Mac e o convidado não tem rota até eles.
As mesmas linhas, seja qual for o agente que você rode
Um time padroniza no Claude Code. Aí alguém traz o Codex para um projeto, o grupo de plataforma roteia um workspace por Bedrock para residência de dados, e um pesquisador começa a rodar Grok. Pelo próprio relato do artigo, três desses quatro não produzem nada na Compliance API.
Um proxy que lê nomes de servidor TLS enxerga os quatro do mesmo jeito, e os
mesmos eventos llm.request, tool.use, command.run, file.read e
file.write saem de todos eles, extraídos do tráfego em vez de concedidos por um
fornecedor. Em um Mac inscrito em um workspace bromure.io eles são transmitidos à
organização por TLS mútuo, junto com egress.firewall para cada veredito do
firewall, credential.exfiltration quando uma credencial isca sai para um host
para o qual nunca foi emitida, e supply_chain.fetch para cada pacote que o
workspace puxou. Esse último dispara mesmo com todas as camadas de imposição de
cadeia de suprimentos desligadas, porque o Bromure separa observar de bloquear. O
fluxo não carrega prompts crus. Ele responde o que o agente fez, não o que o
desenvolvedor pediu.
A frase com que o artigo termina
A frase mais afiada do texto deixa a cobertura para trás: “logs de atividade sozinhos não conseguem dizer se o acesso de um agente é legítimo.”
Isso vale para qualquer log, e é por isso que os motores do Bromure escrevem a linha do tempo eles mesmos em vez de entregar a tarefa a um observador separado. Cada linha vermelha naquela janela registra uma decisão que já aconteceu. Uma linha de cadeia de suprimentos significa um pacote que o agente nunca recebeu. Uma linha de firewall significa uma conexão que nunca abriu. A linha de Guardrails é um push que o host recusou com um 403, que o agente leu como uma falha de API comum, e a linha de corretagem de credenciais é uma isca que nunca virou um segredo de verdade, porque o de verdade nunca esteve na VM.
Você ainda tem que decidir a política. Mas você responde “esse acesso era legítimo” enquanto configura o workspace, não semanas depois enquanto lê linhas.
Onde colocar a sua escuta
Se você roda agentes de código em qualquer escala, ligue a Compliance API. Quatro semanas atrás essa superfície não tinha visibilidade quase nenhuma, e uma semana de transcripts vai te contar sobre o seu próprio time coisas que você não sabia.
Depois faça a segunda pergunta: o que você faz com uma máquina cujo transcript
parece limpo? Em um workspace Bromure a resposta já está na tela. Abra Window →
Trace Inspector para os hosts, Window → Security Timeline para os
veredictos, ou rode bromure-cli trace hostnames e leia cada domínio que aquele
workspace contatou desde que subiu.
O agente não precisa mencionar nada para que aquilo esteja lá. Instale o Bromure Agentic Coding, abra a linha do tempo, e assista a uma instalação.