Blog
Arquitetura

Quantas instruções escondidas chegam ao seu agente? Na minha demo, 8 de 8

Escondi oito instruções numa página com CSS e HTML. A pessoa não vê nenhuma, o leitor do agente pega as oito. E mesmo lendo o texto renderizado com innerText no Chrome, cinco ainda passam. O que eu faria para defender um agente que lê a web.

Escondi oito instruções numa página de previsão do tempo. Na tela, nenhuma aparece. No texto que um leitor de agente extrai do HTML, aparecem as oito. E quando troquei a extração pelo texto renderizado do navegador, que parecia a correção óbvia, cinco continuaram passando.

Em outubro eu escrevi sobre o texto que só a IA lê, com casos reais. Desta vez quis medir.

O que a demo faz

É o quinto item da série Frontend com IA: 05-hidden-text, em TypeScript estrito. Uma página de exemplo recebe oito técnicas, cada uma com uma instrução falsa e fácil de achar com grep: mesma cor do fundo, fonte de tamanho 0, opacity: 0, display: none, aria-hidden="true", comentário HTML, posicionado fora da tela e content num ::after. Um painel mostra o que a pessoa vê. O outro mostra o que o leitor do agente extrai. O placar conta quantas instruções o agente acha e a pessoa não.

Com as oito ligadas, o placar fica em 8 de 8. Dá para ligar uma por vez pela URL, por exemplo só o ::after.

Veja: não tem modelo nenhum aqui. O leitor do agente é um extrator determinístico, parecido com o que muita ferramenta de “ler página” faz antes de mandar o texto para o LLM. Ele junta o texto sem tags, os comentários e o content do CSS (trecho de src/extractor.ts):

const comments = extractComments(withoutScripts);
const withoutComments = withoutScripts.replace(COMMENT_RE, ' ');
const bodyText = stripTags(withoutComments);
const pseudo = extractStyleContents(`${withoutScripts}\n${css}`);
return [bodyText, ...comments, ...pseudo].join(' ');

Então a demo mostra o que chega ao agente. Ela não prova que um LLM obedeceria. Isso depende do modelo, do prompt e das ferramentas que ele tem na mão.

Onde eu errei

Minha primeira reação foi: é só usar o texto renderizado. O innerText do navegador respeita o CSS, e o MDN descreve exatamente isso.

Testei a mesma página da demo no Chrome 156 headless, lendo document.body.innerText. Caíram três técnicas: display: none, comentário e ::after. Passaram cinco: cor igual ao fundo, fonte 0, opacidade 0, aria-hidden e fora da tela. Para o navegador, esse texto está renderizado. Só não dá para ver.

Tem mais um detalhe honesto. A extração “visível” da demo sabe quais classes escondem texto, porque fui eu que montei a página. Uma página de verdade não avisa. É como conferir a mala no raio-x sabendo onde você mesmo guardou o canivete.

Como eu defenderia

Acho que filtrar o HTML ajuda, mas não fecha a porta. Eu montaria a defesa em camadas:

  1. Conteúdo da web entra como dado. O texto extraído vai num bloco marcado como não confiável, separado das instruções do sistema. Isso reduz o risco, sem zerar. A OWASP coloca prompt injection em primeiro lugar justamente por não ter correção completa.
  2. Ação com efeito precisa de outra porta. Se o agente pode aprovar um pedido, essa ferramenta não pode depender só do que ele leu. Aprovação humana ou política deny-by-default, como discuti no post sobre hooks de política.
  3. Logar o que chegou ao modelo. Guardar o texto extraído, e não só a URL, é o que permite explicar depois por que o agente fez o que fez.
  4. Canário no teste. O truque da demo serve para qualquer pipeline: instruções falsas e únicas, uma por técnica, e um teste que falha se alguma delas aparecer na entrada do modelo. A demo tem um teste por técnica em src/extractor.test.ts.

O que muda para você

Se o seu agente lê páginas, PDFs ou e-mails, pegue a página da demo, passe pelo seu leitor e conte quantas instruções chegam. Meu palpite é que o número não vai ser zero. O código está no repositório frontend-ia-demos, e as outras demos da série estão em eliseu.dev/projects.

Sou Tech Lead de IA e esse tipo de fronteira entre o que o agente lê e o que ele pode fazer é o que eu gosto de discutir. Se quiser conversar sobre o seu caso, me chama aqui.

Fontes

esc
  • Home Início
  • Sobre Trajetória e como trabalho
  • Blog Artigos sobre IA, plataforma e liderança
  • Projetos Demos públicos de frontend com IA
  • Currículo Web, PDF, Markdown e texto
  • Setup Hardware e ferramentas
  • Quantas instruções escondidas chegam ao seu agente? Na minha demo, 8 de 8 Arquitetura
  • Classificar ticket com LLM custa 44 vezes mais? O que a Amazon mediu ao trocar o Sonnet por um modelo de decisão Arquitetura
  • Inference hooks do Claude: se o seu servidor de política cair, quem decide é um checkbox Arquitetura
  • Claude Code vazava o e-mail no User-Agent: o que eu checaria amanhã Segurança
↑↓ navegar ↵ abrir esc fechar