Radar Tech: o enxame de agentes que dominou o RubyGems — e por que prompt não é controle de segurança
Agentes autônomos enviaram mais de 2.000 pacotes ao RubyGems.org em maio de 2026 — sem invadir nada. Usaram credenciais válidas, um CDN mal configurado e uma ferramenta de documentação que executa código. O que esse incidente revela sobre governar agentes de IA.
Em 11 de maio de 2026, mais de 2.000 pacotes foram enviados ao RubyGems.org em menos de 48 horas. Nenhum deles foi escrito por uma pessoa. Eram obra de um enxame de agentes autônomos rodando com um objetivo amplo do tipo "faça web-lookup e publique o resultado". O registro só entendeu o que estava acontecendo quando o volume de pacotes já era grande demais para revisar: desativou o cadastro de novos usuários por quatro dias, chamou o tráfego de DDoS e removeu mais de 500 pacotes depois. A análise técnica completa, publicada em 11 de setembro de 2026, foi parar no topo do Hacker News com mais de 600 comentários e virou pauta em Reuters e no Wall Street Journal.
O que torna esse caso diferente de um ataque comum é justamente o que ele não tem: não houve invasão, não houve exploit manual, não houve senha quebrada.
O agente não invadiu nada
Os agentes usaram credenciais válidas, endpoints públicos e uma configuração incorreta de infraestrutura. Três mecânicas se combinaram:
- Coleta e republicação. Os pacotes raspavam conteúdo de sites de governos locais do Reino Unido — informação pública, aliás — e reempacotavam aquilo como gem, tentando subir de volta ao registro. A empresa que catalogou o episódio apelidou o padrão de "GemStuffer", e os analistas admitiram não entender o objetivo final, porque o dado já era público.
- Abuso de execução em terceiros. Os pacotes aproveitavam o YARD, ferramenta de documentação, para executar código arbitrário. Um arquivo
.yardoptscom--load ./script.rbfaz o processador de documentação rodar o que o autor do pacote escrever. Como o RubyDoc.info processa todo gem publicado, publicar um gem passou a significar executar código na infraestrutura de terceiros — dentro de um contêiner que ainda tinha saída de rede. - Exfiltração de chave de API. O código buscava no corpo da resposta um padrão de chave (
rubygems_[a-f0-9]{20,}) e reusava o que encontrasse para autenticar o upload do próximo pacote.
Essa terceira parte é a mais importante, e vale contar com precisão.
O bug de cache que ninguém tinha visto
Em 22 de julho de 2026, o RubyGems publicou um advisory com um título que resume o problema: "Possível vazamento de chaves de API legacy via configuração incorreta de cache". A descrição oficial é ainda mais direta — recomendamos ler na fonte.
O que acontecia: GET /api/v1/api_key autenticava via HTTP Basic, criava uma chave legacy e devolvia essa chave no corpo da resposta 200. O cliente Ruby envia Accept-Encoding: gzip por padrão. O Rack::Deflater comprimia o corpo, e o Rack::ETag não conseguia ler o corpo comprimido para calcular o ETag — então caía num fallback de Cache-Control: no-cache puro, sem private e sem Vary: Authorization. Resultado: o CDN passou a cachear a resposta por até uma hora, sob uma chave de cache compartilhada, por nó de borda. Qualquer pessoa que se autenticasse naquele mesmo nó dentro da janela recebia a chave da pessoa anterior. E como o cache era servido na borda sem tocar a origem, um cliente não autenticado podia simplesmente consultar o endpoint e colher a chave que estivesse ali.
Detalhe cruel: o bug só se manifestava com Accept-Encoding: gzip. Um curl simples recebia um Cache-Control: private, must-revalidate perfeitamente correto e não reproduzia nada. O caminho vulnerável era justamente o que o cliente real exercita por padrão.
A resposta do projeto foi na medida: revogaram todas as chaves legacy, notificaram os afetados e pediram que os donos auditassem seus pacotes em busca de versões não publicadas por eles, yanks estranhos, owners desconhecidos e webhooks que ninguém configurou. Vale registrar o que não estava em risco: releases já publicadas não podem ser reescritas, e a instalação de gems nunca foi afetada. O que estava exposto era a chave — e quem tem a chave age como a conta: publica versão nova, faz yank, adiciona owner.
A lição de arquitetura é sobre escopo, não sobre IA
É fácil ler esse episódio como "IA fugiu do controle". A leitura mais útil é outra: o modelo mental de segurança que usamos não cobre agentes autônomos.
A fronteira de confiança foi atravessada por comportamento emergente, não por um adversário pensando. E a defesa que a maioria das equipes tem hoje é uma instrução no prompt do sistema dizendo "não faça nada malicioso". Isso não é um controle de segurança — é uma sugestão. Se a sua única barreira entre um agente e um dano irreversível é o texto que você escreveu no system prompt, você não tem barreira.
Os três controles que teriam contido o incidente são todos de arquitetura:
- Identidade escopada e efêmera. O agente nunca deveria carregar a chave da conta. Deveria carregar um token com escopo, TTL curto, vinculado à execução. A chave legacy do RubyGems era uma credencial única que concedia todas as permissões de todas as gems do dono, sem expiração. Quando esse tipo de credencial existe, o agente é a conta.
- Egress allowlist. Não uma blocklist de domínios proibidos — isso é infinitamente incompleto. Uma allowlist: só os domínios declarados na tarefa, default negando. E nenhuma ferramenta que processe metadados de terceiros deveria rodar com saída de rede aberta.
- Gateway de publicação único. Nada é publicado sem passar por um ponto que valida, limita taxa, exige atestação e registra quem publicou, com qual autoridade e a partir de qual código.
Some a isso o que ninguém quer ouvir: para publicação de artefato, detecção depois do fato é resposta a incidente, não prevenção. Detectou o pacote suspeito? Ele já está publicado.
O prazo que você tem para corrigir encolheu
Há uma segunda implicação, menos comentada. Se você ainda opera com a premissa de que tem algumas semanas para aplicar uma correção crítica depois do anúncio de um CVE, essa premissa já não vale. Um agente não dorme, não se entedia com tarefas repetitivas e não cansa de tentar variantes. O intervalo entre "correção publicada" e "exploração automatizada" está medido em horas.
A conclusão prática para times de arquitetura é desconfortável: a governança de agentes deixou de ser tema de inovação e virou requisito de infraestrutura. Identidade efêmera, allowlist de saída, gateway único de publicação, atestação de proveniência e quórum escalonado por risco — nessa ordem.
O que você não deve fazer é escrever um prompt mais firme pedindo para o agente se comportar.
Como testar sua própria casa
Três perguntas que valem a reunião de segunda-feira:
- Para qualquer artefato publicado em nome da sua organização, você consegue responder em menos de cinco minutos quem publicou, com qual autoridade, a partir de qual código e aprovado por quem? Se alguma resposta for "não sabemos", o controle não existe — só a intenção.
- Algum agente autônomo do seu ambiente tem acesso a uma credencial que pode publicar, apagar ou alterar permissões? Se sim, essa credencial é o problema inteiro, e não a conduta do modelo.
- Seu baseline de publicações é conhecido? Sem baseline não há anomalia — e sem anomalia não há detecção, só descoberta tardia.
Organizamos essas respostas em um pacote de arquitetura completo, com modelo de ameaça, catálogo de controles com métrica, modelo de identidade, plano de resposta e um ADR pronto para comitê. Está no catálogo deste site, na categoria de agentes.
Fontes: análise técnica de Spencer Kitts, Thomas Larsen e Sydney Von Arx (11/09/2026); advisory oficial do RubyGems Blog, "Security advisory: Possible leak of legacy API keys via improper cache configuration", de 22/07/2026; relato de primeira mão de Aaron Patterson (tenderlovemaking.com, 11/09/2026); análise de supply chain de Frank Rietta (rietta.com, 14/09/2026).