
Encontrei 3 Vulnerabilidades de Segurança na Ferramenta de Acesso do Meu Agente de IA
Eu construí o GeoMart para o Desafio WebMCP da OpenAI: uma loja onde um humano preenche um "resumo do site" ao vivo e não enviado, e um agente de IA usa as ferramentas WebMCP para lê-lo, avaliar equipamentos de pesquisa em relação a restrições físicas reais e elaborar uma cotação que o humano precisa aprovar. A regra do hackathon é clara: cada ação principal deve ser acessível apenas através de uma ferramenta WebMCP, nenhuma rota REST pode duplicá-la.
Eu pensei que tinha coberto isso. Então pedi ao Google Antigravity para tentar quebrá-lo, dei a ele o código-fonte completo e ele encontrou três problemas em cerca de dez minutos.
A primeira análise do Antigravity descobriu que o texto fornecido pelo agente, o raciocínio da cotação, os IDs dos produtos na bandeja de comparação, estavam indo diretamente para a página via innerHTML não escapado. Também encontrou algo pior: POST /api/quotes, o endpoint que cria um pedido de cotação, não tinha proteção alguma. Um script simples de fora de qualquer navegador poderia chamá-lo diretamente e enviar uma cotação sem a intervenção de um humano.
Eu consertei ambos. Escapei em HTML cada string fornecida pelo agente antes que ela chegasse ao DOM. E adicionei uma verificação isTrusted no manipulador de clique do botão de envio, para que um clique simulado por script (element.click(), dispatchEvent) não pudesse acioná-lo. Apenas um clique derivado de hardware passa.
Eu redeployei, me senti bem com isso e pedi um novo teste.
O Antigravity repetiu o ataque exato que havia funcionado antes. Desta vez, ele obteve um 403. Bom. Então ele tentou algo que eu não havia pensado em testar: ele definiu manualmente o cabeçalho Origin em uma chamada fetch() bare Node.js para corresponder ao próprio domínio do meu site.
Ele obteve um 201. A cotação foi enviada. Nenhum navegador envolvido.
Origin não é um segredo. Meu repositório é de código aberto, exigido pelas próprias regras do hackathon. Qualquer um que ler worker.ts pode ver exatamente qual valor minha verificação espera. Um navegador real não pode forjar esse cabeçalho, mas o fetch() do Node não é um navegador e não tem tal restrição. Meu "conserto" apenas verificou "você se preocupou em copiar o nome do domínio", não "você é realmente um navegador".
Se sua verificação de segurança ainda passaria depois que você contasse ao atacante exatamente como funciona, nunca foi uma verificação real. Era um filtro para pessoas que ainda não leram seu código.
Considerei uma abordagem de cookie de sessão a seguir e me convenci a não fazê-lo em cerca de dois minutos, porque ela falha no mesmo teste: um script com acesso HTTP completo pode simplesmente buscar a página primeiro para pegar o cookie e, em seguida, reproduzi-lo na solicitação real. Nenhum navegador necessário ali também. Mesma brecha, forma diferente.
O conserto que funcionou precisava de algo que nunca aparece no repositório. Eu adicionei o Cloudflare Turnstile, verificado no lado do servidor contra um segredo armazenado apenas em um segredo do Worker, nunca comprometido, nunca no pacote do cliente. Eu reproduzi o exato bypass depois: origem correta, nenhum token, 403. Origem correta, token falso, 403. Essa é a diferença entre "um valor que você pode ler" e "um valor que você não pode".
Enquanto perseguia o bypass de origem, o novo teste revelou algo não relacionado: a tabela do banco de dados para armazenar as cotações enviadas nunca havia sido criada. Eu escrevi o arquivo de migração quando construí o recurso e nunca o executei. Cada teste anterior do fluxo "humano clica em enviar" havia apenas exercitado a etapa de rascunho do lado do cliente, draft_quote_notes, que nunca toca o servidor. Todo o ponto do design com humano no loop é que o clique de um humano escreve uma linha no banco de dados. Essa gravação havia sido silenciosamente quebrada o tempo todo, e nada a pegou até que um clique produziu um erro 500.
Essa perseguição me deixou com um teste que agora aplico a cada verificação que adiciono: essa verificação depende de algo que o agente, ou qualquer um que lê seu repositório público, já poderia saber ou derivar?
Cabeçalhos de origem: públicos, em sua própria URL.
Cabeçalhos de referer: mesmo problema.
Um cookie de sessão sem validação do lado do servidor: derivável em duas solicitações.
Um valor que apenas seu servidor computa, que nunca sai do seu servidor: na verdade, um segredo.
Testar adversarialmente um aplicativo voltado para agentes de IA não é opcional se você está reivindicando um limite de aprovação humana. Peça a um agente com acesso total ao código-fonte para tentar derrotar suas próprias reivindicações, especificamente aquelas das quais você mais se orgulha, antes que um juiz ou um atacante faça isso por você.
O GeoMart está ao vivo em https://geomart-webmcp.fpl-test.workers.dev, as ferramentas WebMCP estão documentadas no repositório em https://github.com/dannwaneri/geomart-webmcp, e a mensagem de commit no commit de endurecimento de segurança detalha cada um desses consertos, incluindo aqueles que não funcionaram da primeira vez.
Empresas brasileiras que utilizam agentes de IA devem estar atentas às vulnerabilidades de segurança que podem surgir. O artigo enfatiza a necessidade de testes rigorosos e a implementação de medidas de segurança robustas para proteger dados e operações. A segurança em aplicações de IA é crucial para manter a confiança do usuário e a integridade do sistema.


