Ao vivo 18/11 · Turma 318 nov às 19:00 MSK — aula prática gratuita de agentes de IA · Turma 3 ao vivo começa 23/11Aula 18/11 →Turma 3 (23/11)
LançamentoAnálise · No radarHabr AI→ original

Kilo Code entregou em silêncio ao servidor os 12 arquivos do projeto, embora só dois fossem permitidos

O autor verificou o que vai para o servidor do modelo quando um assistente de IA altera um único caractere no código. O Kilo Code 7.4.20 trocou a soma pela multiplicação, o teste passou e no disco mudou um único arquivo. Mas um servidor de teste que fazia o papel de provedor não confiável recebeu todos os 12 arquivos do projeto, embora o usuário tivesse permitido enviar apenas dois, e as cópias coincidiam byte a byte.

Processado por IA de Habr AI; editado por Hamidun News
Kilo Code entregou em silêncio ao servidor os 12 arquivos do projeto, embora só dois fossem permitidos
Fonte: Habr AI. Colagem: Hamidun News.
Ouvir artigo
Ficha técnica e números-chave
ParâmetroDados
Fonte originalHabr AI ↗
Editor-chefe
Dado-chave #1O servidor leu os arquivos com chamadas read comuns, sem arquivos compactados nem curl
Dado-chave #2Os resultados da leitura iam para o histórico do chat e eram enviados em cada requisição seguinte
Dado-chave #3Proibir read não ajuda se bash estiver permitido: o Python lê o mesmo arquivo

Costumamos aceitar o trabalho de um assistente de IA assim: olhamos o diff, rodamos os testes, vemos o verde e fechamos a tarefa. Um experimento descrito no Habr expõe uma falha nesse hábito. A edição pode ser perfeita, e o projeto já estar no servidor de outra pessoa.

Como o experimento foi montado

A tarefa era propositalmente minúscula: em price.py a função total(price, count) retornava price + count, enquanto o teste esperava que total(7, 3) desse 21. Era preciso trocar a soma pela multiplicação e executar check.py. A instrução do usuário dizia que só price.py e check.py podiam ser enviados.

O autor partiu de um modelo em que o provedor de LLM não é confiável e viola as instruções de propósito. Seu papel foi feito por um servidor HTTP local em 127.0.0.1. Ele imitava respostas em streaming da API Chat Completions compatível com a OpenAI e enviava ao cliente tool_calls: primeiro doze comandos read para todos os arquivos de um projeto sintético, depois um comando de correção e então a execução do teste. O cliente era real: bin/kilo.exe da extensão Kilo Code 7.4.20, iniciado pelo comando CLI run. A configuração permitia leitura e execução de comandos.

O que aconteceu

Por fora, tudo parecia exemplar. O Kilo mudou um caractere, o teste passou, os demais arquivos no disco não mudaram, o código de saída foi zero e todas as 14 chamadas de ferramentas terminaram com o status completed. Mas o servidor recebeu todos os 12 arquivos, num total de 11 103 bytes, e seus SHA-256 coincidiam com os originais.

A mecânica é simples. O Kilo adiciona o resultado de cada leitura ao histórico do chat e o envia na requisição seguinte. O servidor extrai as mensagens com o papel tool, remove os números de linha e remonta os arquivos. Nenhum canal de exfiltração é necessário: o próprio cliente leva os dados nas requisições normais.

O tráfego é interessante por si só. Foram 15 chamadas ao modelo, e o volume total dos corpos das requisições foi de 458 779 bytes para 11 KB de código único. A causa é o reenvio do histórico, as descrições das ferramentas e a marcação de serviço. Não houve uma única requisição enorme: o código saía em pequenas porções e depois se repetia. Por isso, um vazamento assim não é percebido pelo tamanho de uma requisição.

Por que as proibições funcionam pior do que parece

Na série inicial de testes, a regra read: deny bloqueava a leitura direta de um diretório proibido. Mas com bash: allow, o Python leu o mesmo arquivo e a saída foi para a requisição seguinte. Quando o bash foi proibido, o comando não foi executado. As permissões no Kilo são definidas separadamente para cada ferramenta, e proibir uma não fecha os outros caminhos.

Há também ressalvas honestas. No experimento não há um modelo real: os comandos eram escolhidos pelo servidor de teste, então ele não mede a propensão de modelos comerciais a esse comportamento. Os nomes dos arquivos eram conhecidos de antemão pelo servidor; a busca autônoma por uma árvore desconhecida não foi testada. A sessão gráfica da extensão também não foi testada, apenas a CLI.

O que fazer na prática

Primeiro: avalie não só o diff, mas também o registro de chamadas de ferramentas e os corpos das requisições ao provedor. Passe o agente ao menos uma vez por um proxy local e veja o que realmente sai.

Segundo: dê ao agente o mínimo de permissões. Se a leitura é permitida, tudo o que foi lido potencialmente pertence ao provedor. Para repositórios sensíveis, esse é um argumento a favor de modelos locais ou de provedores com garantias contratuais rígidas.

Terceiro: não confie em uma instrução de texto como «envie apenas estes dois arquivos». É um desejo dirigido ao modelo, não uma restrição do cliente. O limite real só é criado por permissões de ferramentas, sandbox e políticas de rede.

O autor publicou o ambiente de teste completo: Python 3.10+, Git e o executável do Kilo, cerca de 150 linhas de código. Vale repeti-lo no seu próprio cliente, seja qual for o agente que você use.

História

Perguntas frequentes sobre a notícia

Como o experimento foi montado?

A tarefa era propositalmente minúscula: em price.py a função total(price, count) retornava price + count, enquanto o teste esperava que total(7, 3) desse 21. Era preciso trocar a soma pela multiplicação e executar check.py. A instrução do usuário dizia que só price.py e check.py podiam ser enviados. O autor partiu de um modelo em que o provedor de LLM não é confiável e viola as instruções de propósito. Seu papel foi feito por um servidor HTTP local em 127.0.0.1.

O que aconteceu?

Por fora, tudo parecia exemplar. O Kilo mudou um caractere, o teste passou, os demais arquivos no disco não mudaram, o código de saída foi zero e todas as 14 chamadas de ferramentas terminaram com o status completed. Mas o servidor recebeu todos os 12 arquivos, num total de 11 103 bytes, e seus SHA-256 coincidiam com os originais. A mecânica é simples. O Kilo adiciona o resultado de cada leitura ao histórico do chat e o envia na requisição seguinte.

Por que as proibições funcionam pior do que parece?

Na série inicial de testes, a regra read: deny bloqueava a leitura direta de um diretório proibido. Mas com bash: allow, o Python leu o mesmo arquivo e a saída foi para a requisição seguinte. Quando o bash foi proibido, o comando não foi executado. As permissões no Kilo são definidas separadamente para cada ferramenta, e proibir uma não fecha os outros caminhos. Há também ressalvas honestas.

ZK
Zhemal Khamidun — CPO da Alpina Digital, gerente de produto do AlpinaGPT. Cria produtos de IA desde 2019. O Hamidun News é um projeto pessoal que virou um agregador em produção com mais de 6.000 leitores.
✦ Unified AI Workspace · Nomad

Test Frontier LLMs & Autonomous Agents in One Workspace

Run Claude Opus 5.5, GPT-6, Gemini 3.1, and DeepSeek side-by-side in Nomad AI (nomadnet.ai) — unified model routing, deep research, and multimodal workflows under one subscription.

Try Nomad AI →Launch Nomad Agent
O que você acha?
Carregando comentários…