Voltar para todas as publicações
Publicado em · por Renaud Deraison

O guarda e o shell discordaram

Em 30 de junho, a Adversa AI divulgou o GuardFall — uma classe de contornos que faz passar truques de bash com décadas de idade direto pelos guardas de comando embutidos em 10 dos 11 agentes de código open source mais populares. A razão é simples e impossível de corrigir nessa camada: o guarda lê o texto, e o bash reescreve o texto antes de executá-lo. O Bromure Agentic Coding nunca apostou que o guarda leria o bash corretamente. Apostou que o comando não importa no momento em que é executado.

O filtro de segurança de um agente de código olhou para a string r''m -rf ~ e viu um comando que não reconheceu, então deixou passar. O bash olhou para a mesma string, jogou fora as aspas vazias e executou rm -rf ~. O filtro e o shell estavam lendo duas linguagens diferentes. Essa lacuna não é um bug em uma ferramenta — é a ideia inteira de guardar um agente por correspondência de padrões nos comandos que ele digita, e a Adversa AI acabou de mostrar que ela falha em dez dos onze agentes que testou.

O guarda de comandos é o recurso ao qual toda ferramenta de código agêntico recorre primeiro. O agente propõe um comando de shell; um filtro inspeciona a string; se parecer destrutiva — rm -rf, um curl … | sh via pipe, um dd para um dispositivo bruto — o guarda a bloqueia ou pede sua confirmação. É a coisa que permite ligar a execução automática e se sentir seguro. Em 30 de junho de 2026, a Adversa AI publicou uma pesquisa, retomada por The Hacker News e SecurityWeek, mostrando que o recurso é teatro.

O que é o GuardFall

Eles o chamam de GuardFall, e não é um CVE. Não há nada para corrigir, porque não é uma falha em um componente — é uma incompatibilidade entre dois deles. Nas palavras da Adversa: "Um guarda inspeciona texto bruto, enquanto o shell do sistema (bash) expande, remove aspas e reescreve o texto antes de executá-lo." O filtro corresponde à string que o modelo emitiu. O bash então passa essa string por remoção de aspas, expansão de variáveis e substituição de comandos antes que um único byte seja executado. Os dois nunca olham para o mesmo comando, então qualquer truque que sobrevive à reescrita mas não à correspondência passa sem obstáculos.

Esses truques são mais antigos do que a maioria das pessoas que usam os agentes. A Adversa os agrupou em cinco classes:

  • Remoção de aspas. r''m são dois tokens para uma regex e a palavra rm para o bash, que descarta as aspas vazias.
  • Expansão de variáveis. rm$IFS-rf$IFS/ parece uma única palavra longa para um correspondente de padrões; o bash expande o Separador de Campo Interno e obtém rm -rf /.
  • Substituição de comandos. $(echo rm) -rf / esconde o verbo perigoso dentro de $( ); o guarda que inspeciona a string externa nunca vê rm.
  • Pipelines codificados. echo <base64> | base64 -d | sh — cada token visível é inofensivo; a carga só existe após a decodificação.
  • Flags destrutivas alternativas. Nenhum rm: find /x -delete, tar -C / -x, sed -i. Uma lista negra construída em torno de rm e dd nunca dispara.

A Adversa lançou esses truques contra onze dos agentes de código e de uso de computador open source mais usados — opencode, Goose, Cline, Roo-Code, Aider, Plandex, Open Interpreter, OpenHands, SWE-agent e o projeto Hermes entre eles, somando cerca de 548.000 estrelas no GitHub entre todos em maio. Dez caíram. O único que resistiu, Continue, resistiu por um motivo específico: em vez de corresponder à string bruta, ele tokeniza o comando do jeito que o bash fará antes de decidir — absorvendo as aspas, resolvendo $IFS, extraindo o comando interno de uma substituição, sinalizando qualquer pipe que termina em sh. Ele modela o shell. É a única coisa que funciona na camada do guarda, e é engenharia real e cuidadosa que os outros dez terão agora de reproduzir, corretamente, e manter correta a cada caso de borda do bash e a cada lançamento.

O AGENTE EMITE UMA STRINGr''m -rf ~GUARDA · casa o texto brutovê os tokensr''m · -rf · ~nenhum rm → permite ✓BASH · reescreve, depois rodadescarta as aspas vaziasrm -rf ~diretório pessoal apagado
Por que o guarda perde. O agente emite uma string; o guarda por correspondência de padrões a lê como escrita e não encontra nada destrutivo; o bash então expande, remove aspas e reescreve a mesma string em rm -rf antes que o veredito do filtro signifique alguma coisa. O guarda e o shell estão olhando para dois comandos diferentes — a premissa inteira do GuardFall.

O problema é a camada, não a regex

A tentação é ler o GuardFall como "dez equipes escreveram filtros fracos". Isso ignora o que a Adversa está dizendo. Sua frase mais afiada não é sobre nenhum agente em particular:

Um agente que pode rodar comandos de shell arbitrários no host do operador, controlado por uma regex que corresponde à string emitida pelo LLM, não é uma defesa. Ele falha enquanto está totalmente habilitado e corretamente configurado, porque a correspondência de string não consegue modelar o que o bash vai rodar.

Totalmente habilitado e corretamente configurado. Isto não é uma má configuração que você possa fechar. O guarda fica na única camada onde ele nunca pode vencer — entre um modelo que escreve strings e um shell que as reinterpreta — e pede a um correspondente de texto que preveja a saída de um expansor Turing-completo. A abordagem tokeniza-e-canoniza do Continue estreita a lacuna ensinando o guarda a pensar como o bash, e é o movimento certo se você vai manter um guarda ali. Mas é um compromisso por agente e por lançamento de superar a análise de um shell que passou trinta anos acumulando maneiras de reescrever um comando. Nove outros agentes populares mostram como é fácil errar.

Os controles compensatórios da Adversa são reveladores. Antes de qualquer correção estrutural, eles mandam você redirecionar o $HOME para um sandbox restrito que mantém o acesso ao projeto mas remove as credenciais, retirar as flags de execução automática, impedir que agentes rodem em pull requests não confiáveis, e tratar todo arquivo de configuração de repositório como código não confiável. Releia essa lista. Não é conselho sobre escrever um filtro melhor. É conselho sobre construir uma caixa em torno do agente para que, quando o filtro perder — e eles estão dizendo que vai perder — o comando que passa aterrisse em algum lugar onde não possa machucar você.

Essa caixa é o produto.

O Bromure nunca pediu ao guarda para ler o bash

O Bromure Agentic Coding parte da suposição que o GuardFall prova: o agente vai, mais cedo ou mais tarde, rodar um comando que você não sancionou. Ele não tenta pegar esse comando lendo-o. Ele roda o agente inteiro — Aider, Goose, opencode, qual dos dez você preferir — dentro de uma VM Linux descartável, e roteia cada requisição de rede por um proxy no host. A pergunta de projeto nunca é "o filtro vai reconhecer este rm?". É "quando o rm rodar, o que ele alcança?".

Passe as próprias cargas do GuardFall por essa caixa.

O ponto do ataque, uma vez que um r''m oculto ou um find /x -delete faz um README com armadilha escapar do guarda, é roubar o que a conta pode alcançar — a Adversa cita ~/.ssh, ~/.aws, credenciais de nuvem, "qualquer coisa que esteja na sua pasta pessoal" — e apagá-lo ou exfiltrá-lo. No Bromure, essas são as coisas que nunca estiveram na caixa. Os segredos reais nunca entram na VM: quando você dá a um perfil uma AWS_SECRET_ACCESS_KEY, um token do GitHub, uma chave da Anthropic, o ambiente do agente recebe um substituto brm_…, e o proxy do host troca o falso pelo valor real no fio, apenas na requisição de saída ao provedor que deve recebê-lo. A mitigação recomendada pela Adversa — mover o $HOME para algum lugar que "mantém o acesso ao projeto mas remove as credenciais" — é uma versão artesanal e parcial do que um perfil Bromure faz por padrão, para cada credencial, sem você ter de scriptar.

SEM — home real, chaves reaiscarga GuardFall rodacat ~/.aws/credentials wJalrXUtn…cat ~/.ssh/id_ed25519 -----BEGIN…atacante obtém chaves válidascontas reais, dano realexfiltraCOM BROMURE — caixa descartável, iscasmesma carga roda (na VM)cat ~/.aws/credentials brm_d4e5f6…cat ~/.ssh/id_ed25519 brm_a1b2c3…PROXY DO HOST — chaves reais nunca entram na VM; injetadas só na requisição verdadeira ao provedoratacante obtém iscas brm_…não autenticam nadahome é um clone descartávelexfil registrada · reset apaga
A carga do GuardFall passa nos dois mundos — o Bromure não impede o comando de rodar. À esquerda: num host normal, o comando injetado lê o material real de ~/.ssh e ~/.aws e o envia; funciona. À direita: dentro do Bromure o mesmo comando roda, mas o diretório pessoal é um clone descartável, as credenciais que ele encontra são iscas brm_… as chaves reais vivem no host, e a tentativa de exfiltração é uma linha registrada no Registro de Segurança. O comando executou e não alcançou nada.

A metade destrutiva aterrissa do mesmo jeito. Um find /x -delete ou um sed -i que escapa do guarda de fato roda — o Bromure não finge que pegou o comando. Ele roda contra um diretório pessoal clonado de uma base compartilhada, numa VM que você pode apagar e resetar para a base a partir de um menu, não de um formulário de incidente. A persistência que uma carga possa deixar morre nesse reset. E porque cada requisição sai pelo proxy do host, o beacon curl … | base64 -d que a classe de pipelines codificados do GuardFall foi feita para esconder não é invisível: é uma linha registrada e atribuível no Registro de Segurança.

O único lugar onde o fio vence o shell

O Bromure mantém sim um guarda de operações destrutivas — seus Guardrails do lado do host, sobre os quais escrevemos depois que um agente do Cursor apagou um banco de dados de produção em nove segundos. E aqui a camada joga a favor do Bromure, porque os Guardrails não vivem onde o GuardFall vive.

O GuardFall é um ataque de texto de shell. Cada uma de suas cinco classes — remoção de aspas, $IFS, $( ), pipelines base64, flags exóticas — é um truque de como o bash analisa uma string. Os Guardrails do Bromure nunca leem essa string. Eles ficam no proxy do host e classificam a chamada de API estruturada que o agente faz a um provedor que ele entende — a requisição HTTPS real ao AWS, ao Kubernetes, a uma forja git, a um banco de dados gerenciado — e retornam um 403 firme nas destrutivas, no fio, onde um agente comprometido na VM não pode desligá-las. Quando uma requisição chega a essa camada, ela já é um DeleteDBInstance analisado, não uma string de aspas e cifrões. Não há reescrita de shell para contrabandear nada, porque não há shell no caminho. A técnica inteira do GuardFall precisa de um bash entre a verificação e a ação; no caminho dos Guardrails, não há um.

O que isto delimita, para deixar claro

O comando ainda roda

O Bromure é isolamento, não interceptação. Uma carga GuardFall que escapa do guarda do seu próprio agente vai executar dentro da VM. O que o Bromure muda é o raio de dano: um home descartável, credenciais-isca, um caminho de saída registrado. Se você precisa que o comando em si seja recusado, isso é trabalho do guarda do seu agente — e o GuardFall é o motivo pelo qual você não deveria depender dele.

Destruição local é descartabilidade, não um bloqueio

Um find /x -delete contra arquivos dentro da VM não é uma chamada de API de provedor, então os Guardrails não o controlam. A resposta à destruição dentro da VM é que a VM é descartável e o trabalho real vive num repositório montado e no host, não que o delete foi impedido. Resetar para a base, não reverter.

A substituição cobre as credenciais que você configura

A troca brm_… protege os segredos que você põe num perfil — chaves de modelo, tokens de nuvem e git, endpoints de bancos de dados gerenciados. Uma senha que você cola à mão num arquivo dentro da caixa, ou um token que um script escreve em disco no meio da sessão, é apenas um arquivo. Guarde os segredos no broker, não no espaço de trabalho.

A saída é registrada, não proibida por padrão

O beacon de exfiltração aparece no Registro de Segurança; isso é atribuição, não prevenção. Nada real sai porque as credenciais são iscas, mas se você precisa que a VM seja impedida de falar com hosts arbitrários, isso é uma política de rede que você ainda define.

A parte que se generaliza

O GuardFall é um enunciado limpo de uma regra que a categoria inteira não para de reaprender: você não pode tornar um agente seguro pedindo a um filtro que preveja o que seu comando vai fazer. O modelo escreve uma string, e em algum lugar abaixo dele um shell, um cliente de API, um gerenciador de pacotes ou um navegador reinterpreta essa string com suas próprias regras. Toda defesa que inspeciona a saída do agente e torce para que ela corresponda ao comportamento final está apostando contra essa lacuna, e a lacuna sempre vence — venceu aqui em dez dos onze agentes que estavam, nas palavras da Adversa, totalmente habilitados e corretamente configurados.

O Bromure Agentic Coding não faz essa aposta. Ele assume que o comando vai rodar, que o guarda vai às vezes falhar, e que o agente que você convidou pode ser virado contra você por um README que você nunca escreveu. Então ele torna o lugar onde o comando roda não valer a pena atacar: chaves reais no host, iscas na caixa, uma VM descartável, um bloqueio firme reservado ao fio onde nenhum shell pode reescrevê-lo, e um registro de tudo que tentou sair. Você pode rodar qualquer um dos dez agentes que o GuardFall quebrou — o resultado é a mesma caixa descartável de qualquer jeito. É gratuito e open source.