Uma Ferramenta Esquecida Derruba a Allowlist Inteira

TV
Thiago Victorino
8 min de leitura
Uma Ferramenta Esquecida Derruba a Allowlist Inteira

Dois times publicaram as mesmas duas conclusões na mesma semana, sem citar um ao outro.

A primeira veio do time do Kiro, na AWS, explicando por que reconstruíram o modelo de permissões compartilhado entre o agente de CLI e o agente de IDE: “Em ambos os clientes, as permissões eram por ferramenta: uma única intenção como negar leituras de .env precisava ser configurada separadamente para cada ferramenta capaz de ler arquivos (read, glob, grep, inteligência de código). Esqueça uma e o agente ainda acessa o arquivo por outra ferramenta.”

A segunda veio de Magnus Hedemark, escrevendo sobre o QM, o gerenciador de frota que a Y Combinator abriu como código aberto depois de provisionar mais de 50 agentes Hermes como assistentes pessoais para funcionários e descobrir que até uma frota desse tamanho é difícil de administrar: “Uma empresa não é uma pessoa com um histórico de chat muito longo.”

As duas frases falam da mesma coisa. Uma regra de permissão tem uma unidade, e a maioria dos times escolheu a unidade errada.

A capacidade é a unidade da regra

A substituição feita pelo Kiro cabe em uma linha: “Um deny em fs_read bloqueia toda ferramenta que lê arquivos (read_file, grep_search, file_search e qualquer ferramenta de leitura futura) sem enumerá-las individualmente.”

O trecho que sustenta tudo é “qualquer ferramenta de leitura futura”. Uma allowlist enumerada é uma lista que envelhece. Cada ferramenta adicionada ao harness depois que a regra foi escrita alarga silenciosamente o que a regra permite, e ninguém abre um chamado, porque nada quebrou. O agente apenas ganhou uma segunda porta para uma sala que você trancou uma vez. Busca semântica, um novo backend de inteligência de código, um servidor MCP que alguém plugou numa quinta-feira: cada um deles consegue ler o .env enquanto a sua denylist continua nomeando read e parecendo satisfeita.

Classes de capacidade invertem o padrão. Você escreve a intenção uma vez, contra fs_read, fs_write ou exec, e toda implementação presente e futura daquela capacidade herda a regra. Ferramentas novas chegam já governadas. Enumerar vira a exceção que você justifica, em vez do mecanismo do qual você depende.

Já argumentamos que permissões pertencem ao lugar onde os dados vivem e já medimos com que frequência hierarquias de instrução se resolvem mal em tempo de execução. Classes de capacidade são a peça de sintaxe que faltava para tornar as duas coisas praticáveis. Uma regra que você não consegue expressar de forma compacta é uma regra que você não vai manter.

Três semânticas de casamento para um mesmo produto

Antes da unificação, as próprias superfícies do Kiro discordavam sobre o que uma regra significa: “a CLI usava allowedCommands/deniedCommands baseados em regex, enquanto a IDE usava casamento por prefixo para trustedCommands e casamento por substring para sua denylist.”

Regex, prefixo e substring são três teorias diferentes sobre o que uma regra cobre. Uma entrada de denylist por substring com rm casa com charm, com format e com qualquer caminho que contenha essas duas letras, enquanto uma regra por prefixo com git deixa passar sudo git. Um engenheiro de segurança escrevendo uma política para uma empresa produz três resultados de enforcement distintos, dependendo de qual cliente o desenvolvedor abriu.

A correção é tediosa e correta: uma única linguagem de casamento em todas as superfícies, glob para caminhos, com a mesma semântica onde quer que a regra seja avaliada. Se você roda agentes em mais de um lugar, e hoje quase todo mundo roda (terminal, IDE, CI, um runner hospedado), comece perguntando se os dois lugares que leem a política concordam sobre o que ela diz. O texto da política vem depois.

Deny sempre vence, e o agente não edita as regras

As políticas do Kiro são escritas em Cedar, descrita pelo time como “uma linguagem de política formalmente verificada”. Elas compõem entre escopos com semântica de deny sempre vence, podem ser distribuídas por administradores corporativos via MDM e sustentam uma invariante que a maioria das montagens caseiras viola sem perceber: “o agente não pode modificar os próprios arquivos de permissão.”

Vale checar essa invariante hoje. Em um repositório típico, a configuração do agente fica dentro do repositório, e o agente tem acesso de escrita ao repositório. O teto é, portanto, consultivo. Um agente que pode editar a própria denylist não tem denylist; tem um arquivo de sugestões com boas intenções e um histórico no git.

A separação também é arquitetural. Sobre por que o motor de permissões roda como processo próprio, o time do Kiro escreveu: “Vimos em tentativas anteriores que bibliotecas compartilhadas não impõem uma fronteira forte o suficiente… Um processo isolado torna a separação real.” É o mesmo raciocínio que produziu contenção no nível do sistema operacional, aplicado uma camada acima. Uma fronteira que mora dentro daquilo que ela restringe é decoração.

Cinco escopos, porque autoridade é organizacional

O QM chega ao problema pela ponta oposta. Onde o Kiro pergunta o que um agente pode tocar, o QM pergunta sob a autoridade de quem o agente está agindo. Hedemark aponta que o QM define cinco tipos de escopo em src/types.ts: pessoal, canal, grupo, time e organização. Os turnos são roteados para adaptadores de harness intercambiáveis para Pi, OpenCode, Codex e Claude Code.

O modo como ele descreve a divisão é o mais limpo que li: “O loop executa o turno. O plano de controle mantém registro da organização na qual aquele turno significa alguma coisa.”

A consequência é operacional, e a maioria dos times ainda não encarou. “Quando um funcionário sai, a autoridade dele precisa sair junto.” Se as permissões dos seus agentes vivem em dotfiles de laptops e em configuração por repositório, desligar um funcionário não desliga os agentes dele. As credenciais talvez sejam revogadas. A autoridade delegada, aquela aprovação permanente que deixa algum fluxo agir em nome daquela pessoa, continua rodando até alguém lembrar que ela existe.

É também por isso que os adaptadores de harness importam mais do que parecem. O fornecedor por baixo dos seus agentes vai mudar. Seu organograma, seus escopos e suas obrigações de auditoria não vão. Um plano de controle soldado a um único harness precisa ser reconstruído toda vez que o mercado se move. O stack de contenção só é durável se o andar de cima sobreviver aos andares de baixo.

A parte honesta: uma postura nomeada não é enforcement

Hedemark evita vender o que está descrevendo. Ele ancora cada afirmação sobre o QM em um commit específico do repositório, escreve explicitamente como usuário do Hermes Agent e enquadra o texto como “um contraste útil”, descartando de saída a leitura de comparação objetiva entre produtos. Depois lista o que ainda falta: Auto é a postura de segurança padrão; Strict “pausa para aprovação humana em toda chamada de ferramenta do harness, exceto duas que encerram o turno sem efeito”; e “o Docker local e o backend AWS padrão não impõem a allowlist de domínios de egresso do QM.”

O último item é o mais afiado. Um workspace rotulado com uma allowlist de egresso, rodando no backend padrão, tem um rótulo. Os pacotes saem assim mesmo. Toda camada de governança tem alguma versão disso: um nome de postura em um arquivo de configuração que nenhum componente em execução está de fato verificando.

Nenhum dos dois textos traz medição de eficácia. Ambos são descrições de arquitetura, sem resultados. A página do Kiro está publicada sem data e omite cargo das pessoas creditadas nela. Leia os dois como argumentos de design que convergiram de forma independente, o que já é indício de uma restrição real. Prova de que essas implementações aguentam um ataque, nenhum dos dois oferece.

Faça isso agora

Quatro verificações, cerca de uma hora, sobre o setup de agentes que você já opera.

Conte as portas de uma regra. Escolha uma permissão que você acredita ter, do tipo “agentes não leem segredos”. Escreva a intenção em uma frase. Depois liste toda ferramenta do seu harness capaz de satisfazer aquela intenção: read, grep, glob, busca semântica, inteligência de código, cada servidor MCP, shell. Se a contagem de ferramentas for maior que a contagem de regras, você tem o bug do Kiro agora.

Compare as semânticas de casamento. Descubra onde cada superfície avalia as regras. É regex, prefixo, substring ou glob? Se duas superfícies respondem diferente, sua política tem dois significados e você vinha lendo apenas um deles.

Veja quem pode escrever no arquivo de política. Rode ls -l nele e confira se ele está dentro do workspace que o agente pode editar. Se estiver, trate o modelo de permissões inteiro como consultivo até movê-lo.

Diga seus escopos em voz alta. Pessoal, time, organização: quais deles existem como objetos com enforcement no seu setup, em vez de convenções? Depois teste o que importa: se alguém pedir demissão amanhã, o que revoga a autoridade sob a qual os agentes daquela pessoa estão agindo, e em quanto tempo?

O time que corrigir apenas a primeira verificação já melhora. O time que responde a quarta tem um plano de controle.


Fontes

A Victorino ajuda organizações de engenharia a reescrever permissões de agente por ferramenta em classes de capacidade e escopos organizacionais que sobrevivem ao próximo harness: contato@victorino.com.br | www.victorino.com.br

Todos os artigos do The Thinking Wire são escritos com o auxílio do modelo LLM Opus da Anthropic. Cada publicação passa por pesquisa multi-agente para verificar fatos e identificar contradições, seguida de revisão e aprovação humana antes da publicação. Se você encontrar alguma informação imprecisa ou deseja entrar em contato com o editorial, escreva para editorial@victorino.com.br . Sobre o The Thinking Wire →

Se isso faz sentido, vamos conversar

Ajudamos empresas a implementar IA sem perder o controle.

Agendar uma Conversa