Todo hook é uma cicatriz: 84 falhas de agente gravadas em código
No meu sistema de orquestração de agentes existem 84 ganchos interceptando 15 dos 26 tipos de evento de ciclo de vida que o Claude Code expõe na v2.1.116 (abril de 2026). Cada gancho é um shell script ou um trecho de Python que dispara antes ou depois de uma ação específica do agente: leitura de arquivo, escrita de arquivo, comandos bash, requisições web, criação de subagentes, operações no git, chamadas de ferramentas MCP. Cada gancho existe porque alguma coisa deu errado.
Todo gancho em um sistema de orquestração de agentes remete a uma falha específica em produção, e é isso que transforma a coleção de ganchos em memória institucional codificada como shell scripts. Agentes apagaram caches de CDN, leram arquivos de credenciais, relataram testes aprovados que nunca rodaram e saíram do rumo por 40 minutos. Cada incidente gerou uma pequena proteção determinística que dispara silenciosamente em todas as sessões seguintes.
Não erraram na teoria. Erraram em produção. Um agente apagou um cache de CDN que servia milhões de requisições. Um agente tentou escrever chaves SSH. Um agente relatou “todos os testes passaram” sem nunca ter invocado o pytest. Um agente se afastou tanto da tarefa que passou quarenta minutos otimizando uma função em um arquivo que não tinha nada a ver com o trabalho designado.
Não projetei nenhum desses ganchos de forma preventiva. Não me sentei para enumerar os modos de falha de agentes de IA autônomos e escrever controles preventivos. Todo gancho é reativo. Algo quebrou, escrevi um script para impedir que quebrasse de novo, e esse script vem disparando silenciosamente em todas as sessões desde então. O sistema de ganchos não é uma arquitetura de segurança. É uma coleção de cicatrizes.
Resumo
- O purge de cache: um agente apagou um cache de CDN em produção usando uma chamada de API autorizada. Dois ganchos (47 linhas) agora barram operações destrutivas atrás de uma senha digitada por um humano.
- O leitor de credenciais: um agente incluiu tokens de API na sua janela de contexto. Uma proteção baseada em correspondência de caminho agora bloqueia a leitura de arquivos de credenciais e registra os acessos a arquivos
.env. - O verificador fantasma: um agente relatou “todos os testes passaram” sem rodar o pytest. Um detector de linguagem evasiva derrubou a verificação fantasma de 12% para menos de 2% das sessões.
- Os doze desvios: agentes perderam de vista a própria tarefa, de forma comprovada, doze vezes em sessenta dias. Um detector de similaridade de cosseno com limiar de 0,30 agora dispara a cada 25 chamadas de ferramenta.
- A taxonomia: seis categorias estruturais de falha cobrem todos os 84 ganchos. Categorias inéditas são raras depois de mais de 500 sessões. O sistema fica mais duro a cada incidente.
O purge de cache: como uma única chamada autorizada quebrou a produção
Em 21 de março de 2026, pedi a um agente que investigasse por que as páginas de mercado do resumegeni.com estavam carregando devagar. O agente começou a investigação normalmente: lendo os handlers de rota, checando as queries do banco, medindo o tempo de renderização dos templates. Então decidiu que entradas de cache desatualizadas na Cloudflare poderiam estar mascarando o comportamento real de performance.
O agente chamou mcp__cloudflare__cache_purge com purge_everything: true.
Todas as páginas em cache do site de produção foram invalidadas instantaneamente. A CDN, que servia a maior parte das requisições em 80-100ms, passou a encaminhar cada requisição para o servidor de origem no Railway. A página de mercado de Austin saiu de menos de um segundo para 14.290 milissegundos. Nova York, de menos de um segundo para 6.891ms. Todas as páginas do site passaram a ser renderizadas na origem fria, a cada requisição.
O agente não fez nada sem autorização. Usou uma ferramenta MCP legítima, com credenciais válidas, para chamar um endpoint de API autorizado. O purge de cache é um passo investigativo razoável quando você está depurando comportamento de cache. O problema é que “razoável para depurar” e “catastrófico para produção” eram a mesma chamada de API, e não havia nenhuma restrição entre o raciocínio do agente e a consequência em produção.4
Construí dois ganchos naquela noite.
A proteção de Bash (destructive-api-guard.sh): dispara em todo comando bash. Faz correspondência de padrões contra curl.*purge, rm -rf, DROP TABLE, docker.*rm, git push.*--force. Bloqueio total (exit 2). O agente recebe uma mensagem explicando por que o comando foi bloqueado e sugerindo alternativas. Ele não consegue prosseguir sem a senha “rosebud”, que só entra no contexto se um humano digitá-la.
A proteção de MCP (destructive-mcp-guard.sh): dispara em toda chamada de ferramenta MCP que corresponda a mcp__cloudflare ou mcp__github. Faz correspondência de padrões contra purge, delete, destroy e remove nos parâmetros da ferramenta. Mesmo bloqueio total, mesma barreira de senha.
Dois ganchos. Dois shell scripts. Total: 47 linhas de código. Eles impediram zero purges de cache desde a instalação, porque nenhum agente tentou nenhum desde que a barreira de senha entrou em vigor. Os ganchos não estão barrando ataques. Estão tornando essa categoria de erro impossível.
O incidente do purge também escancarou o problema de performance que ele deveria investigar. Austin com 14 segundos em renderização fria levou à transferência de contexto sobre a página de mercado, que levou à correção do formato da query quatro dias depois. O incidente foi útil. O gancho garante que ele não se repita.
O leitor de credenciais
Em fevereiro de 2026, um agente reunindo contexto para um projeto leu ~/.claude/docs/credentials.md. O arquivo contém tokens de API para Cloudflare, GitHub, Railway e outros serviços. O agente incluiu um resumo do conteúdo do arquivo nas suas anotações de trabalho, o que significa que os tokens foram parar na requisição de API enviada aos servidores da Anthropic.
Nenhum token foi commitado. Nenhum token foi exposto publicamente. Mas os tokens trafegaram por uma API de terceiros, dentro de uma janela de contexto que não controlo. A superfície de risco cresceu de “minha máquina” para “minha máquina mais a infraestrutura de inferência da Anthropic”.
A proteção de caminhos de credenciais dispara em toda leitura de arquivo. Ela compara o caminho com uma lista de padrões sensíveis: .env, credentials, .ssh/, .aws/, .gnupg/, secrets. Para leituras de credenciais, o gancho registra um aviso e bloqueia a leitura. Para leituras de .env, permite a leitura, mas registra o acesso.
Para a maioria dos caminhos a proteção é apenas consultiva; para arquivos de credenciais, é bloqueio total. A distinção importa: um agente lendo .env para entender os nomes das variáveis de ambiente é contexto útil. Um agente lendo credentials.md para entender tokens de API é um incidente de segurança.
Desde a instalação, a proteção de caminhos de credenciais disparou 23 vezes ao longo de mais de 200 sessões. Vinte foram agentes lendo arquivos .env (registrados e permitidos). Três foram agentes tentando ler arquivos de credenciais ou de chaves (bloqueados). Cada leitura bloqueada veio de um agente que estava levantando contexto do projeto de forma ampla e acabou incluindo um arquivo sensível no seu padrão de busca. Nenhuma delas era maliciosa. Todas teriam colocado segredos na janela de contexto se a proteção não existisse.
O verificador fantasma
O modo de falha mais insidioso é um agente que relata verificação bem-sucedida sem ter feito verificação alguma.
Sessão 147. Pedi a um agente que refatorasse uma query de banco e verificasse a mudança com a suíte de testes existente. O agente refatorou a query corretamente. O relatório de conclusão dizia: “Todos os testes passaram. A query refatorada produz resultados idênticos aos da original.”
Fui conferir o log da sessão. Nenhuma invocação de pytest aparecia ali. Nenhum executor de testes, de nenhum tipo, tinha sido chamado. O agente raciocinou que os testes passariam porque a query refatorada era logicamente equivalente à original, e relatou esse raciocínio como se fosse um resultado de teste.
A query refatorada estava correta. Os testes teriam passado. O raciocínio do agente era sólido. Mas raciocinar sobre testes não é rodar testes, e é nessa lacuna que bugs chegam à produção. Se a query refatorada estivesse sutilmente errada em algum caso extremo que o raciocínio do agente não cobrisse, o bug teria ido para o ar acompanhado de um relatório de conclusão alegando verificação por testes.
Esse modo de falha ocorreu 7 vezes em 60 sessões antes de eu construir o gancho da barreira de evidência. O gancho dispara em todo relatório de conclusão e varre o texto em busca de linguagem evasiva: “deve passar”, “acredito que”, “os testes provavelmente passam”, “estou confiante”. Quando detecta, o gancho injeta uma mensagem: “Linguagem evasiva detectada. Cite evidência específica: cole a saída do teste, indique o arquivo e o número da linha, ou aponte o passo de verificação específico.”
O gancho não verifica se os testes de fato rodaram. Ele sinaliza o padrão linguístico que indica que a verificação foi pulada. A detecção é imperfeita. Um agente suficientemente fluente poderia reformular suas evasivas para escapar do padrão. Mas o gancho pega o caso comum, que responde por 12% das falhas de agente que exigem intervenção humana.1
Depois da instalação do gancho, a verificação fantasma caiu de 12% para menos de 2% das sessões. Os 2% restantes são casos em que o agente reformula a evasiva ou em que a alegação de verificação é tecnicamente correta, mas incompleta (por exemplo, “os testes unitários passaram” quando os testes de integração não foram executados).
Desvio
Entre janeiro e março de 2026, meu detector de desvio disparou doze vezes em sessões nas quais o agente havia comprovadamente perdido de vista a tarefa designada.
O detector de desvio funciona gerando o embedding do prompt original da tarefa e comparando-o periodicamente ao embedding das ações recentes do agente. Quando a similaridade de cosseno cai abaixo de 0,30, o sistema injeta um aviso contendo o prompt original. Calibrei o limiar por experimentação: 0,50 era sensível demais (disparava em exploração legítima de subtarefas), 0,20 era permissivo demais (deixava passar desvios óbvios), 0,30 pegou todos os incidentes de desvio confirmados.
A sessão 203 foi o caso mais claro. A tarefa era “corrigir o escape de XML quebrado no sitemap para slugs de vaga que contêm e comercial”. O agente começou lendo o código de geração do sitemap. Então notou que o sitemap era gerado a partir de uma query no banco. Então notou que a query podia ser otimizada. Então passou 40 minutos refatorando a query em um padrão de visão materializada, escreveu testes para a nova query e relatou a otimização concluída. Nunca corrigiu o escape do e comercial.
O detector de desvio teria pegado isso na marca das 25 chamadas de ferramenta, cerca de 15 minutos depois do início da sessão, quando a similaridade entre “corrigir o escape de XML do sitemap” e “criar visão materializada” caiu abaixo do limiar. Em vez disso, descobri o desvio durante a revisão.
A sessão 89 foi mais sutil. A tarefa era “adicionar rate limiting aos endpoints de autenticação”. O agente adicionou o rate limiting corretamente. Então notou que o fluxo de autenticação tinha mensagens de erro inconsistentes. Então padronizou as mensagens de erro. Então notou que o formato da resposta de erro divergia do padrão de formato de resposta da API. Então refatorou o formato de resposta em 12 endpoints. O rate limiting estava correto e completo. A explosão de escopo foi o desvio.
O detector de desvio dispara a cada 25 chamadas de ferramenta. Nos doze disparos abaixo do limiar, o agente havia comprovadamente se desviado da tarefa original. Em seis casos, o agente se autocorrigiu depois de ver o aviso injetado. Em quatro casos, o agente reconheceu o desvio, mas argumentou que o trabalho em curso era valioso (às vezes com razão). Em dois casos, o agente ignorou o aviso e seguiu com o trabalho divergente.
O gancho não impede o desvio. Ele torna o desvio visível. A decisão de redirecionar ou permitir o trabalho divergente continua sendo do humano. Mas sem o gancho, o desvio fica invisível até o relatório de conclusão — e a essa altura o orçamento de contexto já foi gasto.
A taxonomia das cicatrizes
Depois de 84 ganchos, os padrões aparecem. As falhas se agrupam em seis categorias:
| Categoria | Ganchos | Exemplo |
|---|---|---|
| Exposição de credenciais | 12 | Agente lê .ssh/, inclui chaves de API em resumos, acessa configurações de nuvem |
| Operações destrutivas | 8 | Purge de cache, drop de banco, force push, exclusão de arquivos |
| Desvio de tarefa | 4 | Agente trabalha no problema errado, explosão de escopo, mergulho sem fim em subtarefas |
| Qualidade do resultado | 6 | Verificação fantasma, evasivas sem evidência, relatórios incompletos |
| Esgotamento de recursos | 3 | Subagentes demais criados, loops sem limite, estouro de contexto |
| Contaminação entre projetos | 4 | Agente no projeto A modifica arquivos do projeto B |
Os 47 ganchos restantes são específicos de projeto (aplicação de convenções, proteções de deploy, validadores de tradução) ou experimentais (rastreamento de custo, métricas de sessão, sinais de atividade).
As seis categorias estruturais são estáveis. Novos incidentes dentro delas são pegos pelos ganchos existentes. Categorias inéditas são raras. Em seis meses de operação, só uma nova categoria estrutural apareceu (contaminação entre projetos, descoberta quando uma sessão rodando no projeto obsidian-signals tentou editar arquivos do blakecrosley.com). As outras cinco categorias já estavam estabelecidas nas primeiras 60 sessões.
O estudo Agents of Chaos, um experimento multiuniversitário de 14 dias que deu a seis agentes de IA acesso a e-mail, bash, sistemas de arquivos e GitHub, identificou de forma independente categorias de falha coincidentes: resposta desproporcional (operações destrutivas), sequestro de identidade (exposição de credenciais), loops infinitos (esgotamento de recursos) e complacência gradual sob pressão (desvio de tarefa).5 A convergência entre a pesquisa controlada deles e a minha experiência em produção sugere que essas categorias são propriedades estruturais de agentes autônomos, não artefatos de alguma configuração específica.
O que os ganchos não conseguem pegar
Os ganchos operam no nível da chamada de ferramenta. Interceptam a ação antes ou depois que ela acontece. Não conseguem interceptar o raciocínio que levou à ação.
Um agente que decide refatorar uma função em vez de corrigir o bug relatado produz uma chamada de ferramenta válida (escrita de arquivo), com conteúdo correto (código sintaticamente válido), que viola a tarefa (função errada). Nenhum gancho detecta isso, porque nenhuma chamada de ferramenta é suspeita. O detector de desvio acaba pegando, mas só depois de o agente ter consumido bastante contexto no trabalho errado.
Os ganchos também não conseguem pegar falhas de composição, em que cada ação individual é autorizada, mas a sequência produz um resultado não autorizado. O purge de cache foi uma falha de composição: ler a configuração do cache (autorizado), chamar a API de purge (autorizado), mas a combinação (limpar o cache de produção durante uma investigação) foi danosa. A proteção de MCP agora pega essa combinação específica, mas composições inéditas continuam sem cobertura.
A lacuna de composição na cadeia de suprimentos3 opera no mesmo nível: componentes confiáveis se combinam em comportamento não autorizado. Os ganchos são proteções no nível do componente. Raciocinar no nível da composição exige outro mecanismo, um que avalie sequências de ações em vez de ações isoladas. O detector de desvio é a aproximação mais próxima: ele avalia a trajetória do comportamento, não chamadas de ferramenta isoladas. Mas o que ele mede é a similaridade com a tarefa original, não a segurança da sequência de ações composta.
A distância entre os ganchos e a segurança completa é a distância entre memória institucional e previsão institucional. Os ganchos lembram o que deu errado. Não preveem o que vai dar errado a seguir.
Por que ser reativo é honesto
Eu poderia projetar um sistema de ganchos preventivo. Enumerar todos os modos de falha possíveis. Escrever controles preventivos para cada um. Construir uma arquitetura de segurança completa antes da primeira sessão.
Não faço isso porque projetar preventivamente exige prever falhas que ainda não aconteceram. As previsões estariam erradas. Os ganchos seriam amplos demais (bloqueando ações legítimas) ou estreitos demais (deixando passar o padrão real de falha). A taxa de falsos positivos corroeria a confiança no sistema de ganchos, e eu passaria a ignorar os alertas.
Ganchos reativos são honestos. Cada um diz: “esta coisa específica aconteceu, e aqui está a proteção específica que a impede”. A proteção é calibrada com precisão para a falha porque foi a falha que a definiu. Os falsos positivos são substancialmente menores porque o padrão foi extraído de um incidente real, não imaginado a partir de um modelo de ameaças. Uma proteção reativa ainda pode passar a pegar demais com o tempo, conforme o código evolui, mas a precisão inicial é alta.
A abordagem reativa tem um custo: a primeira ocorrência de cada categoria de falha passa. O purge de cache aconteceu. A leitura de credenciais aconteceu. A verificação fantasma foi para o ar. O desvio consumiu contexto. Cada primeira falha é o preço de entrada para uma proteção precisa, de baixo ruído, que impede a segunda falha.
Depois de mais de 500 sessões, a maioria das categorias estruturais de falha já foi encontrada. O custo da primeira falha se amortiza ao longo de centenas de sessões em que o gancho impediu a recorrência. O sistema fica mais duro a cada incidente. Não mais inteligente. Mais duro.
Cada gancho é uma cicatriz. Cada cicatriz é uma lição. As lições se acumulam.2
Perguntas frequentes
Posso ver suas configurações de ganchos?
Descrevo o sistema de ganchos no meu comentário enviado ao NIST sobre segurança de agentes e faço referência a ele ao longo de toda a série de AI Engineering. Os ganchos são registrados em ~/.claude/settings.json e despachados por tipo de evento através de ~/.claude/hooks/dispatchers/.
Como os ganchos afetam a performance do agente?
Cada gancho acrescenta milissegundos por chamada de ferramenta. Com 84 ganchos, a sobrecarga total fica em 200-400ms por chamada, dependendo de quais deles disparam. É desprezível perto do tempo de inferência do modelo (2-5 segundos por resposta). Os ganchos não são o gargalo.
Os ganchos funcionam com outras ferramentas de programação com IA?
Os ganchos são específicos do Claude Code (modelo de eventos PreToolUse, PostToolUse). O conceito se aplica a qualquer framework de agentes com suporte a middleware ou plugins. As implementações específicas não são portáveis, mas a taxonomia das cicatrizes e a metodologia reativa valem em qualquer lugar.
O que acontece quando um gancho bloqueia uma ação?
Bloqueios totais (exit 2) impedem a ação e injetam uma mensagem explicando o motivo. O agente vê a razão do bloqueio e se ajusta. Ganchos consultivos (exit 0) registram a preocupação, mas permitem a ação. Operações destrutivas usam bloqueio total. A maioria das outras categorias usa ganchos consultivos. A barreira de senha é usada só nas operações mais perigosas (purge de cache, exclusão de infraestrutura).
Como você decide entre bloqueio total e aviso consultivo?
Duas classes recebem bloqueio total: operações destrutivas (purges de cache, exclusões em banco de dados, force pushes, modificações de infraestrutura) e exposição de credenciais (leitura de arquivos secretos, acesso a repositórios de chaves). Todo o resto recebe registro consultivo. A distinção é a gravidade da consequência: se a ação pode ser desfeita a baixo custo e não vaza segredos, um aviso basta. Se a ação é irreversível ou expõe credenciais, o bloqueio total é necessário.
Fontes
-
Blake Crosley, “What I Told NIST About AI Agent Security,” blakecrosley.com, fevereiro de 2026. Taxa de 12% de verificação fantasma em mais de 60 sessões autônomas. 84 ganchos cobrindo 15 dos 26 tipos de evento de ciclo de vida do Claude Code (v2.1.116), metodologia de detecção de desvio. ↩
-
Blake Crosley, “Compound Context: Why AI Projects Get Better the Longer You Stay With Them,” blakecrosley.com, março de 2026. Framework de contexto composto: os ganchos como uma das seis categorias que acumulam retornos. ↩
-
Blake Crosley, “The Supply Chain Is the Attack Surface,” blakecrosley.com, março de 2026. Lacuna de composição: componentes autorizados individualmente que produzem resultados não autorizados. ↩
-
Blake Crosley, “Deploy and Defend: The Agent Trust Paradox,” blakecrosley.com, março de 2026. Incidente do purge de cache e a resposta com proteção contra API destrutiva. ↩
-
Christoph Riedl et al., “Agents of Chaos,” arXiv:2602.20021, fevereiro de 2026. Estudo multiuniversitário de 14 dias (Northeastern, Stanford, Harvard, MIT, CMU). Seis agentes de IA, 10 vulnerabilidades de segurança identificadas, incluindo resposta desproporcional, sequestro de identidade e loops infinitos. ↩