Olá a todos!
Disclaimer habitual antes de começar: sou utilizador do Claude, uso o Claude Code, uso LLM’s privados e não escondo isso a ninguém. Portanto, quando falo mal de um agente de código concorrente, façam o desconto que quiserem. Só que desta vez não é uma questão de gosto pessoal nem de qual o modelo que escreve melhor Python. É uma questão de um CLI ter estado a copiar o repositório inteiro dos utilizadores para a nuvem de uma empresa, sem avisar, sem forma de desligar, e sem que houvesse uma única linha na documentação a admitir que aquilo estava a acontecer. Se isto não vos incomoda, provavelmente ainda não perceberam bem o que aconteceu. Vamos lá.
O que se passou, em três frases
No dia 12 de julho de 2026, um investigador que assina como “cereblab” publicou uma análise ao nível do fio, wire-level, do Grok Build CLI na versão 0.2.93. Traduzindo do técnico: ele pôs-se a olhar para tudo o que saía da máquina enquanto usava a ferramenta, pacote a pacote. E descobriu que o Grok Build não estava só a enviar os ficheiros de que precisava para responder. Estava a empacotar o repositório todo, com o histórico completo de commits, e a mandá-lo para um bucket de Google Cloud Storage chamado grok-code-session-traces, gerido pela xAI.
Reparem numa coisa antes de avançarmos: o problema aqui não é o Grok ler os ficheiros que precisa de ler para trabalhar. Isso é o funcionamento normal de qualquer agente de código na nuvem. O modelo vive num datacenter, não na tua máquina, portanto para responder tem de receber contexto. Toda a gente que usa este tipo de ferramentas assina esse contrato, mesmo que não o leia. O problema é outro, e é muito maior.
A parte debaixo do nosso nariz colectivo: o canal fantasma
O Grok Build corria dois canais de dados ao mesmo tempo.
O primeiro é o que toda a gente espera: os ficheiros que o agente abre para fazer a tarefa vão como contexto para o modelo. Racional, previsível, controlável. Se não queres que ele leia um ficheiro, não o mandas ler. Simples.
O segundo canal é que muda tudo. Em paralelo, em segundo plano, a ferramenta empacotava o workspace inteiro num git bundle e enviava-o por um endpoint separado, POST /v1/storage, para aquele bucket de armazenamento. E aqui está o número que devia fazer qualquer pessoa parar: num repositório de teste de 12 GB, o canal do modelo moveu cerca de 192 KB de tráfego relevante para a tarefa. O canal de armazenamento moveu perto de 5,1 gigabytes, em 73 pedaços. Todos os 83 pedidos de storage devolveram HTTP 200. Zero falhas.
Deixem-me repetir isto por outras palavras, porque é o coração da história. A ferramenta precisava de 192 KB para responder à pergunta. Enviou 5,1 GB. A diferença não é margem de erro. É o teu código todo, incluindo o que o agente nunca abriu, incluindo commits que apagaste da árvore de trabalho mas que continuam no histórico, incluindo aquele ficheiro que puseste num canto a pensar “isto ninguém vai ver”.
O investigador não se limitou a ver tráfego a passar. Ele capturou o upload, clonou o git bundle que foi enviado, e recuperou de lá um ficheiro que tinha dito explicitamente ao Grok para não abrir. Verbatim. Com o marcador de canário lá dentro, CANARY-XR47P2-NEVERREAD. O ficheiro que ele mandou o agente não tocar viajou na mesma para a nuvem da xAI, porque estava commitado no repositório e o bundle leva tudo o que está sob controlo de versão.
“Mas tu disseste-lhe para não ler, a culpa é tua”
Esta é a defesa preguiçosa que já apareceu nos comentários do Hacker News, e convém desmontá-la já, porque é exatamente o tipo de raciocínio que deixa passar problemas destes.
Um deny de permissão impede o agente de LER o ficheiro para dentro da conversa. Não impede o upload do bundle. São duas coisas completamente diferentes que acontecem em sítios diferentes do código. Podes fazer --deny "Read(secret.txt)" e o agente recusa educadamente ler o ficheiro, diz-te que está bloqueado por uma política de permissões, tudo muito bonito. E depois o mesmo ficheiro, intocado, vai à boleia no git bundle na mesma. Clonas o corpo do pedido capturado e está lá.
A única coisa que efetivamente mantém um ficheiro fora do bundle é pô-lo no .gitignore, porque o bundle só carrega ficheiros sob controlo de versão. Ou seja: a proteção que funciona não é nenhum toggle nem nenhuma permissão do Grok. É uma decisão de Git que tomaste (ou não) muito antes de teres instalado a ferramenta.
E agora a cereja no topo do bolo, que é onde eu passo de irritado a genuinamente zangado.
O toggle que não fazia nada
O Grok Build tinha, como tantas destas ferramentas, uma opção de “Improve the model”, melhorar o modelo. É o botão que carregas a pensar “pronto, agora os meus dados não são usados para treino, estou descansado”. É o gesto de higiene digital que todos fazemos.
Não fazia diferença nenhuma para o upload.
Desligar o “Improve the model” não parava o envio do git bundle. O upload do repositório inteiro continuava alegremente, com o toggle ligado ou desligado. A documentação da xAI descrevia esse controlo como uma opção sobre se as conversas novas são usadas para treino. Nunca prometeu que desligá-lo impedia o armazenamento remoto de tudo. É uma daquelas distinções que, no papel, até se defende: “não treinar” não pode logicamente significar “não enviar dados”, porque um modelo na nuvem não consegue responder sem receber contexto. Concordo com a lógica. O problema é que os utilizadores precisavam de um controlo separado, documentado, para o sync do repositório inteiro. E esse controlo não existia. Nem o controlo, nem a documentação, nem o aviso.
Pior ainda: a xAI vendeu o Grok Build como “local-first”. Os materiais de lançamento diziam, e cito a ideia, que nada do teu codebase era transmitido para os servidores da xAI durante uma sessão. Os dados no fio dizem exatamente o contrário. Isto não é uma nuance de interpretação. É uma afirmação de marketing que os pacotes de rede contradizem diretamente.
Consentimento partido
Vou parar um segundo na palavra que interessa: consentimento.
Toda a gente que trabalha com estas ferramentas aceita um certo nível de risco. Eu aceito. Quando uso o Claude Code, sei que o contexto que dou vai para um datacenter da Anthropic. Faço as minhas pazes com isso, escolho o que meto no repositório, uso ZDR quando faz sentido, e sigo em frente. Isto é uma decisão informada. Sei o que estou a trocar e por quê.
O que o Grok Build fez não foi isso. O “Improve the model” sinalizava controlo sobre partilha de dados. O “local-first” sinalizava que o código ficava na máquina. Nenhuma das duas afirmações resiste à evidência do fio. Quando um programador não consegue tomar uma decisão informada sobre o que a ferramenta partilha, o consentimento está partido, independentemente da intenção da empresa.
E aqui quero ser justo, porque a honestidade obriga. O investigador é o primeiro a dizê-lo, e eu repito: isto prova transmissão e armazenamento. Não prova que a xAI treinou modelos com o teu código, não prova que algum funcionário abriu os teus repositórios, não prova que todas as contas se comportavam exatamente da mesma maneira. O bucket grok-code-session-traces até pode existir para continuidade de sessão, telemetria de debug ou logging operacional, e não para treino. A distinção importa, e confundir as duas coisas seria exagerar a descoberta.
Mas reparem: mesmo na leitura mais generosa possível, mesmo assumindo que a xAI é um santo e nunca olhou para nada, o problema mantém-se inteiro. Porque o problema não é o que a xAI faz com os dados depois de chegarem. O problema é que os dados chegaram lá sem tu saberes, sem forma de recusar, e depois de te terem dito que não iam. O dano à confiança é o mesmo quer os dados durmam esquecidos num bucket quer alimentem o próximo Grok. A questão de segurança e a questão de privacidade não dependem da boa-fé da empresa. Dependem do controlo que tu tinhas. E não tinhas nenhum.
Testa tu mesmo, don’t take my word for it.
Uma das coisas que mais gosto nesta história, e que devia ser o padrão em toda a divulgação de segurança, é que o cereblab não te pede para acreditares na palavra dele. Publicou um harness reprodutível para correres na tua própria máquina.
O repositório está aqui: github.com/cereblab/grok-build-exfil-repro
O princípio é limpo. Corres tudo localmente, contra o teu próprio tráfego, com uma conta descartável e segredos falsos de canário. Não há uma única credencial real envolvida. A ferramenta captura o tráfego do próprio Grok com mitmproxy e depois reconstrói o repositório a partir do que saiu pelo fio. Precisas de macOS ou Linux, do mitmproxy (brew install mitmproxy), de git, de python3, e do Grok Build CLI instalado e com login feito (usa a tal conta descartável, por favor).
O fluxo, na prática, são quatro passos:
# 1. Confiar no certificado do mitmproxy e arrancar o proxy de captura
./scripts/setup-proxy.sh
# 2. Plantar um repositório canário (com .env falso e um ficheiro marcado "nunca ler")
./scripts/make-canary-repo.sh
# 3. Correr o Grok pelo proxy, dizendo-lhe para NÃO abrir nada
./scripts/run-capture.sh ./canary
# 4. Reconstruir o que saiu da máquina
./scripts/verify.sh
O prompt que dás ao Grok é, literalmente, “reply OK, do not open any files”. Responde OK, não abras ficheiro nenhum. E mesmo assim o verify.sh vai procurar o git bundle no corpo dos pedidos capturados, cloná-lo, e fazer grep pelo marcador de canário que estava dentro do ficheiro que mandaste não abrir. Se ele imprimir o marcador, o repositório inteiro, incluindo esse ficheiro nunca-lido e o histórico completo, saiu da tua máquina.
Isto é o que uma boa divulgação de segurança parece. Não é um post de LinkedIn com um screenshot recortado e uma seta vermelha. É um harness que qualquer pessoa com um terminal pode correr e verificar em dez minutos. O writeup completo ao nível do fio, com o apêndice de evidências e os SHA-256, está no gist do investigador, ligado a partir do README. Se és do tipo que não acredita em nada sem ver os hashes, tens-nos lá.
E já agora, uma nota que não é acessória: a ferramenta que apanhou isto, o mitmproxy, é gratuita e está ao alcance de qualquer um. Não foi preciso um laboratório da NSA. Foi preciso alguém curioso o suficiente para olhar para o próprio tráfego. Isto devia ser um hábito, não um acontecimento.
E a xAI? Silêncio, e um interruptor escondido
Um dia depois da análise sair, o mesmo investigador voltou a testar e a coisa mudou. O servidor passou a devolver trace_upload_enabled: false e apareceu uma flag nova, disable_codebase_upload: true. Ou seja: houve uma mitigação do lado do servidor. Alguém na xAI virou um interruptor e os uploads pararam, pelo menos naquela máquina e naquela conta.
E é aqui que a história passa de “bug grave” para “gestão de crise que devia envergonhar qualquer empresa séria”.
À data de 13 de julho de 2026, a xAI não emitiu nenhuma declaração pública sobre o incidente. Nenhum aviso de segurança. Nenhuma explicação sobre o âmbito, quantos utilizadores foram afetados. Nenhuma clarificação sobre políticas de retenção do material já enviado. Nenhuma confirmação de que os repositórios e segredos já recolhidos foram apagados do bucket. O changelog oficial listava a versão 0.2.98 como a mais recente a 12 de julho, sem uma palavra sobre comportamento de upload de repositórios. A página de estado da xAI não mostrava nenhum incidente declarado. A correção chegou por uma flag escondida no servidor, sem comunicação nenhuma.
Pensem no que isto significa na prática. Se correste o Grok Build num codebase com credenciais reais antes da correção, aquelas credenciais foram, muito provavelmente, transmitidas. E a nova opção disable_codebase_upload nem sequer traz funcionalidade de auditoria decente. Podes virar o interruptor, mas não consegues verificar facilmente o que foi enviado antes, nem confirmar que a definição está mesmo a funcionar. Corrigir em silêncio é melhor do que não corrigir, admito. Mas corrigir em silêncio e deixar os utilizadores no escuro sobre o que já lhes saiu da máquina não é transparência. É gestão de reputação.
O que fazer se usaste isto
Chega de indignação. Vamos ao concreto, que é para isso que este blog existe.
Se em algum momento correste o Grok Build CLI 0.2.93 dentro de um repositório que continha segredos, a assunção segura é uma só: trata essas credenciais como comprometidas. Não “possivelmente”. Comprometidas. E age em conformidade.
Roda tudo o que possa ter estado num .env ou em qualquer ficheiro commitado. Chaves de API, passwords de bases de dados, tokens de cloud, chaves de assinatura, credenciais de webhooks. Apagar o ficheiro local não invalida uma credencial que já foi exposta, portanto revoga e reemite de verdade, não te limites a limpar a pasta. Inspeciona também o histórico de Git, porque o bundle leva o histórico todo, e aquele segredo que julgaste ter removido num commit posterior continua lá atrás, acessível a quem tenha o bundle.
Se por alguma razão precisas de continuar a usar a ferramenta, não confies só num número de versão. A mitigação observada foi do lado do servidor, o que significa que o comportamento pode variar entre contas e ao longo do tempo sem que a versão mude. Enquanto a xAI não documentar uma garantia de produto sobre isto, com letra a sério e não um tweet, a única postura sã é assumir que qualquer coisa que o agente possa ler pode sair da máquina. Para as equipas de empresa há a opção de Zero Data Retention, que segundo a documentação da xAI impede a persistência de dados na camada de inferência. Existe também menção a um mecanismo de .grokignore para excluir diretórios, mas atenção: pelo que se percebe, esse mecanismo não está documentado na documentação enterprise oficial, portanto verifica que funciona na tua versão antes de dependeres dele para a tua vida.
E se me perguntam a mim, sem rodeios: não corras a CLI de consumidor em repositórios com algoritmos proprietários, dados de clientes, informação regulada, trabalho de segurança por publicar, ou código de terceiros coberto por confidencialidade, até o comportamento da tua conta estar verificado e a xAI documentar o controlo. Isto não é paranóia. É a mesma prudência que já devias ter com qualquer ferramenta que lê a tua máquina.
A lição que ultrapassa a xAI
Ia terminar a bater na xAI, que é fácil e até apetece, mas seria desonesto parar aí. O padrão é maior do que uma empresa e um CLI.
As ferramentas de IA que leem ficheiros locais operam, cada vez mais, com níveis de acesso que tornam a recolha não divulgada de dados arquitetonicamente possível. Não digo provável, digo possível, que já é suficiente para mudar o cálculo. O Grok Build distingue-se de dois modos: pela escala, um repositório inteiro em vez dos ficheiros lidos, e pela falta de divulgação, nada disto estava documentado. Mas o risco de base, o de uma ferramenta ler mais do que devia e mandar para onde não devias saber, esse partilham-no todos. Incluindo, sejamos honestos, o Claude Code que eu uso.
A diferença que interessa não é a marca. É o que consegues verificar. Para quem trabalha em indústrias reguladas, ou com código proprietário, o que atravessa o fio importa mais do que o que uma página de definições promete. Uma página de definições é uma intenção. Um pacote de rede é um facto. E entre uma intenção e um facto, quando o assunto é a tua segurança, escolhe sempre o facto.
Por isso o meu recado final não é “não uses o Grok”. É mais simples e mais desconfortável: instala o mitmproxy esta semana e olha, uma vez que seja, para o que sai da tua máquina quando corres as ferramentas em que confias. Não porque desconfias de todas. Mas porque descobriste, hoje, que “local-first” no material de marketing e “local-first” no fio podem ser duas coisas completamente diferentes. E a única pessoa que vai verificar a diferença por ti és tu.
Fiquem bem, rodem essas chaves e lembrem-se que se não controlam o vosso LLM, não controlam nada.
Abraço
Nuno
Fontes e leitura adicional: a análise original ao nível do fio e o harness reprodutível do investigador cereblab estão em github.com/cereblab/grok-build-exfil-repro; a discussão no Hacker News; cobertura na ByteIota, na Crypto Briefing, na Glitchwire e a análise que separa o provado do especulado na explainx.ai.
