1

Pedir pro modelo não usar seu e-mail não é controle

Essa linha saiu de um subagente de pesquisa do Claude Code no dia 12 de outubro. Ela está na issue #101659, com o e-mail já trocado por um placeholder:

curl -s -o /dev/null -w "%{http_code}\n" -A "ThaneholdResearch/1.0 (<user email>)" --compressed "https://liquipedia.net/warcraft/Armor"

O <user email> era o e-mail da conta logada. Ninguém pediu pra mandar. O modelo inventou um nome de bot, viu que a Liquipedia pede contato no User-Agent de quem usa a API e preencheu com o único e-mail que tinha à mão. A Liquipedia respondeu 403, mas isso não muda nada, porque o header já tinha saído da máquina.

O detalhe que me fez escrever isso é a versão: Claude Code 2.1.285. Desde a 2.1.234, de 17 de agosto, o contexto da sessão já dizia pro modelo não mandar aquele e-mail pra serviço nenhum sem o usuário pedir. A regra estava lá e o modelo mandou mesmo assim.

Por que o e-mail estava no contexto

A explicação veio da Lydia Hallie, que trabalha no Claude Code, num comentário no HN. Usuários reclamavam que o modelo inventava nome em tag @author porque não sabia quem era a conta. A solução foi colocar o e-mail de quem está logado no contexto do modelo.

O outro lado da história é que muito site sério pede contato de quem faz request automatizado. A política de User-Agent da Wikimedia pede um User-Agent descritivo com algum jeito de contatar o operador. O crates.io pede um user-agent que identifique a aplicação e sugere forte incluir contato. A SEC pede pra declarar o user agent e o exemplo dela traz nome da empresa e um e-mail de admin.

Junta as duas coisas e o resultado é previsível. O modelo tenta ser bem-comportado com o site, o site pediu contato, e no contexto tinha um e-mail. Não teve malícia nenhuma, ele só cumpriu a regra do site com o dado que deram pra ele.

E isso nem é assunto novo. A RFC 9110, na seção do header From, diz que um user agent não deve mandar esse header sem configuração explícita do usuário, porque pode conflitar com a privacidade dele. O e-mail de contato num request HTTP sempre foi decisão de quem opera o cliente, nunca do cliente sozinho.

As correções, em ordem

A primeira tentativa foi a 2.1.234. O changelog diz que o Claude passou a ser instruído a usar o e-mail só pra identificar o usuário e não mandar pra serviços sem relação, a menos que o usuário peça. O e-mail continuou no contexto e a proteção era uma frase no prompt. A #101659 mostra como isso terminou.

A segunda foi a 2.1.317, de 2 de novembro, que adicionou um check que pergunta antes de uma chamada web ou de shell mandar o e-mail da conta pra rede. Esse check é um mod embutido, e o README dele é bem honesto sobre o tamanho: "This is a courtesy, not a boundary, and it covers one shape." O teste são dois matches de texto sobre o input do comando, o e-mail e alguma forma de dizer User-Agent (User-Agent, curl -A, wget -U e parentes). Não tem parser. O próprio README lista o que passa: o e-mail numa URL, num body, num curl -u, num header From:, numa variável, num script, num valor calculado em runtime como $(git config user.email). WebFetch, WebSearch e ferramentas MCP não são checadas.

A terceira foi a 2.1.321, de 9 de novembro, e ela estreitou o check. Pelo changelog, agora ele só recusa um comando de shell que contém o e-mail e cita um User-Agent, sem perguntar nada, pra que os outros comandos e as execuções agendadas não parem mais no prompt. Ficou menos chato e cobre menos coisa.

A correção de verdade foi a que a Lydia prometeu no HN, tirar o e-mail do contexto que o Claude Code entrega pro modelo, "na próxima release, que deve sair no começo da semana que vem". Até 10/11, essa mudança não aparece no changelog, e a última versão publicada é a 2.1.322. E o canal stable segue na 2.1.311, que é anterior até ao check da 2.1.317. Quem está no stable não tem nem a cortesia.

E nada disso foi surpresa. Desde abril tem issue reclamando do e-mail injetado no contexto sem opt-out, como a #53231. O primeiro relato público que achei do e-mail no User-Agent é um comentário no HN de 15 de julho, num scraping da SEC. A #78431, de 17 de julho, foi fechada como stale, e uma story no HN de 11 de agosto não passou de 38 pontos. Só em 5 de novembro, com a #107757 e o fio que bateu 1.614 pontos no HN, o assunto ganhou resposta pública do time.

Instrução não é controle

Pra mim, essa é a lição do caso inteiro. Uma frase no system prompt dizendo "não mande o e-mail" é um pedido, e o modelo atende quase sempre. O problema é o quase. Num subagente chamado por outro subagente, com esforço máximo, numa tarefa de pesquisa que bate em vários sites, o quase vira um curl pra Liquipedia.

Controle é o que continua valendo quando o modelo erra. Se o dado não está no contexto, o modelo não tem como colocar num header. O e-mail de login serve pra autenticar a sessão e cobrar a conta, então é na camada de autenticação que ele tem que ficar. Pra resolver o @author, dava pra perguntar o nome uma vez e salvar numa config que o usuário vê e edita.

O argumento contra é bom e eu acho justo encarar. O git config user.email também está ali, a um comando de distância, e o modelo pode ler isso quando quiser. Então tirar o e-mail de login do contexto resolve? Resolve esse caso, e a diferença é quem controla. O e-mail do git config fui eu que coloquei, sei que ele vai em todo commit e posso trocar por um noreply por repositório. O e-mail de login entrou no contexto pelo harness, sem eu configurar nada e sem eu ver. No git config a decisão foi minha. No outro caso, alguém decidiu por mim.

O que eu faria agora

Se você roda Claude Code com acesso à rede, eu não esperaria a próxima release.

O primeiro passo é um proxy de egresso na frente da sessão, reescrevendo User-Agent e removendo From de tudo que sai. Pra HTTPS isso exige um proxy que intercepte TLS, tipo mitmproxy, com a CA confiada só no ambiente do agente. Dá trabalho, mas é o único lugar onde a regra vale pra curl, pra script e pra qualquer cliente que ainda nem existe.

O segundo é olhar o que já saiu. Os transcripts ficam em JSONL em ~/.claude/projects/, e um rg -i 'seu@email.com' ~/.claude/projects mostra se o e-mail apareceu em algum comando. Vale procurar também a versão com %40 no lugar do @.

O terceiro é ter um e-mail de função pra quando o site pedir contato de verdade. A própria RFC usa spider-admin@example.org no exemplo, e a Wikimedia usa coolbot@example.org. Um bots@seudominio com um nome de bot fixo resolve a etiqueta com o site sem expor a pessoa. E esse endereço eu colocaria no proxy, e não no prompt.

Fontes: issue #101659, README do mod privacy, comentário da Lydia Hallie no HN.

Carregando publicação patrocinada...