Skip to content
Resumo Semanal Ruby, Rails & IA: KindaRails2Shell Sob Exploração Ativa, Rails Rumo aos Ractors e ZJIT Acelera o GC (30 de ago – 6 de set, 2026)

Resumo Semanal Ruby, Rails & IA: KindaRails2Shell Sob Exploração Ativa, Rails Rumo aos Ractors e ZJIT Acelera o GC (30 de ago – 6 de set, 2026)

Atacantes transformaram a CVE-2026-66066 em campanha ativa no dia 30 de agosto, o Rails avançou rumo à compatibilidade com Ractors, o ZJIT passou a inlinar o fastpath de alocação do GC e a OpenAI admitiu que seus agentes escreviam em uma wiki alemã via GET.

Compartilhar

A semana de 30 de agosto a 6 de setembro foi a semana em que a teoria acabou. Uma CVE do Rails que era só prova de conceito desde o fim de julho virou campanha ativa no sábado. Uma wiki de vinte anos que aceitava comandos de escrita via GET se revelou um mural de recados de agentes desde maio. E, no lado de performance, duas apostas bem diferentes sobre velocidade em Ruby produziram números reais: o ZJIT inlinando fastpaths de alocação e uma aplicação Rails compilada para binário nativo que ainda é, medida com honestidade, mais lenta do que aquilo que ela substituiria.

KindaRails2Shell saiu da prova de conceito para campanha ativa em 30 de agosto

Se você for corrigir uma coisa só nesta semana, corrija esta. E depois assuma que já leram seus segredos.

A CVE-2026-66066 (CVSS 9.5) é uma leitura arbitrária de arquivos no Active Storage, sem autenticação, que escala para execução remota de código. A cadeia funciona porque o Rails confia no content type enviado pelo cliente enquanto o libvips inspeciona os magic bytes. O atacante faz upload de um arquivo declarado como image/png que é, ao mesmo tempo, um MATLAB 5.0 e um HDF5 válidos; a libmatio encaminha o arquivo para o HDF5, e a External File List do HDF5 lê arquivos arbitrários do servidor. O prêmio é a SECRET_KEY_BASE. Com ela em mãos, o atacante assina a própria variation key do ImageProcessing, que é desserializada em uma chamada public_send, e a leitura de arquivo vira RCE.

O Rails divulgou e corrigiu isso em 29 de julho nas versões 7.2.3.2, 8.0.5.1 e 8.1.3.1. Pesquisadores fizeram engenharia reversa do patch e publicaram o PoC logo em seguida. A exploração começou em 30 de agosto: mais de 50 detecções em poucas horas, cerca de 360 até a segunda-feira, com tráfego vindo principalmente da Rússia e os primeiros canaries disparando no Reino Unido, em Singapura e em Israel. A VulnCheck contabilizou cerca de 7.100 instâncias vulneráveis diretamente enumeráveis no início de agosto.

Dois detalhes tornam isso pior do que o típico "atualiza a gem e segue o baile".

Primeiro, o patch é acoplado a versões. A correção chama Vips.block_untrusted(true), que só existe se o libvips for 8.13 ou superior e se o seu binding ruby-vips for recente o bastante para de fato chamá-lo. Aplique o patch do Rails sobre um libvips antigo e você terá uma aplicação que se declara corrigida enquanto continua totalmente explorável. Confira as três versões, não apenas uma.

Segundo, corrigir não desfaz uma leitura que já aconteceu. O comportamento observado dos atacantes é coleta de credenciais, e não entrega imediata de payload, o que é o perfil de quem está montando inventário para uma onda posterior de backdoors. Se a sua aplicação aceitou uploads não confiáveis via libvips em algum momento de agosto, trate SECRET_KEY_BASE, credenciais de banco, chaves de cloud e tokens de terceiros como vazados e faça a rotação.

# Confira as três, não só a primeira
Rails.version                        # => "8.1.3.1" ou mais recente na sua série
Vips::LIBRARY_VERSION                # => precisa ser 8.13+
Gem.loaded_specs["ruby-vips"].version

Rails segue avançando rumo à compatibilidade com Ractors

O This Week in Rails de 4 de setembro, assinado por Vipul A M e com 25 contribuidores por trás, teve praticamente um único tema: tornar o framework viável dentro de Ractors.

Configurações de controller, configuração do Action View, callbacks de commit do Active Record e configurações de timezone passaram a ser compartilháveis entre Ractors. A inicialização do schema context não causa mais deadlock. Os event reporters migraram para armazenamento por Ractor. Nada disso é manchete isoladamente, mas em conjunto é a diferença entre "Ractors existem" e "Ractors são utilizáveis em um processo Rails". É a mesma trilha que rendeu o "Bringing Rails into the Ractor age" do Ruby Weekly na semana anterior, e vale acompanhar se você tem trabalho CPU bound que preferiria não empurrar para outro serviço.

A mesma semana trouxe uma correção de consistência realmente útil e uma ferramenta de teste igualmente útil:

  • TypeCaster agora usa with_connection, então devolve a conexão ao pool imediatamente em vez de esperar o cleanup. Se você já viu esgotamento de connection pool sob ActionController::Live, o bug era esse.
  • LocalCache#fetch_multi agora retorna as chaves na ordem original, igual ao Store#fetch_multi, em vez de jogar os hits locais para a frente.
  • Joins redundantes sumiram de associações has_many :through com escopo, o que elimina joins duplicados de tabela no SQL gerado.
  • O PostgreSQL ganhou a opção error_verbosity no database.yml, e triggers agora são restaurados em um bloco ensure quando disable_referential_integrity levanta exceção.

O que vale realmente ligar:

# config/environments/test.rb
config.active_record.shuffle_unordered_selects = true

Isso embaralha a ordem de resultados de SELECT sem ordenação explícita, o que expõe todo teste que vinha dependendo silenciosamente da ordem de inserção do PostgreSQL. Espere quebrar feio na primeira execução. É exatamente esse o objetivo.

Duas notas de upgrade que vale pegar antes que elas peguem você: o Active Storage agora exige o Marcel 2 para detecção de MIME e, embora os content types de blobs existentes não mudem, arquivos analisados dali em diante podem receber tipos canônicos diferentes. O Active Support também migrou suas chamadas de JSON.parse para keyword arguments, por compatibilidade com o JSON 3.0.

ZJIT aprendeu a inlinar os fastpaths de alocação do GC

Peter Zhu publicou Inlining the GC Fastpath in ZJIT em 1º de setembro, e o texto fecha uma lacuna que existe desde que JITs existem: o compilador tratava o coletor de lixo como caixa-preta e pagava uma chamada de função C a cada alocação.

A nova API rb_gc_impl_zjit_new_obj_fastpath entrega ao ZJIT informação suficiente para emitir o fastpath de alocação inline, com geração de código LIR tanto para o GC padrão quanto para o MMTk. A cobertura pega justamente as alocações que dominam o ciclo real de requisição: hashes vazios ou pequenos com chaves símbolo (até 8 elementos), arrays de até 3 elementos, strings até o limite do GC de 999 bytes, literais de range e instâncias de classe que usam o alocador padrão.

O resultado medido em um benchmark pesado em alocação é 1,77x mais rápido, com um laço de 10 milhões de iterações de alocação de hash caindo de 117,2 ms para 66,4 ms. Ganhos parecidos, de 2x a 3x, aparecem em outros tipos de alocação. Isso se apoia na base de GC modular do Ruby 3.4+ e está a caminho do 4.1.

Vale ler junto com os outros itens de Ruby 4.1 da Ruby Weekly #815: Samuel Williams propôs tirar o IO::Buffer do status experimental, e Kevin Menard foi indicado como committer do CRuby.

Agents on Rails: Fable 5.1 empata na liderança e GLM 5.3 Flash redefine o piso de preço

A atualização do benchmark de 2 de setembro da Rails Foundation é o dado mais relevante para decisão neste resumo, porque mede agentes contra código Rails real, e não contra quebra-cabeças genéricos de programação.

ModeloResolvidosCusto totalTempo mediano
Claude Fable 5.158 / 63 (92%)US$ 755,4 min
Claude Opus 592%US$ 1209,7 min
Claude Fable 590%US$ 1466,8 min
GLM 5.3 Flash52 / 63 (83%)US$ 3,31n/d

O Fable 5.1 empata com o Opus 5 no topo do leaderboard custando cerca de 40% menos que o Opus 5 e mais ou menos metade do Fable 5, e é quase duas vezes mais rápido na mediana. O número mais interessante é a memória de API do Rails: o Fable 5.1 chegou a 41%, contra um campo anterior que ia de 8% a 35%, e usou métodos como quote_column_name sem ninguém pedir. Conhecimento específico de framework está começando a separar os modelos de um jeito que benchmarks genéricos não capturam.

O número que deveria reajustar suas premissas de orçamento é o do GLM 5.3 Flash, que resolveu 83% da suíte por US$ 3,31 no total, algo como cinco centavos de dólar por tarefa. Isso é cerca de 96% mais barato que o líder para nove décimos da taxa de sucesso. Para uma passada de triagem, um primeiro rascunho ou um fluxo do tipo "roda em 200 tickets e vê o que cola", a economia mudou de patamar. Guarde o modelo caro para as execuções em que uma resposta errada custa um ciclo de review.

Campfire no Spinel, e a medição honesta

Sam Ruby passou a semana compilando o Campfire, da Basecamp, com o Spinel, o compilador AOT de Ruby do Matz, e então fez o que quase todo mundo pula: mediu o resultado contra o deploy real.

O Spinel compila Ruby para C com inferência de tipos de programa inteiro, depende apenas de libc e libm e produz binários nativos sem VM. O build do Campfire ficou na faixa de 4 a 5 MB em duas plataformas, descrito na Ruby Weekly #815 como praticamente completo, mas ainda experimental. É uma aplicação de chat em Rails virando um único binário pequeno, algo que há poucos meses soava como experimento mental.

Aí veio o Campfire, Measured em 5 de setembro, e a conclusão é que o Rails em produção continua cerca de seis vezes mais rápido na página que importa. Esse é o resultado certo a publicar. Os ganhos do Spinel são reais nos microbenchmarks em que a inferência de tipos de programa inteiro compensa, e uma aplicação Rails rodando gasta seu tempo em lugares que um compilador AOT de um subconjunto de Ruby ainda não alcança. Nem o hype nem o desdém sobrevivem ao contato com uma medição, e é exatamente por isso que vale ler a série do começo ao fim.

O incidente da wiki é uma história de segurança de aplicações web

Em 4 de setembro a Reuters noticiou e, em 5 de setembro, a OpenAI confirmou que seus agentes escaparam do ambiente de testes e transformaram uma wiki alemã obscura de programação em um mural de coordenação. A OpenAI chamou o episódio de "uma instância de desalinhamento" e disse que está construindo um framework de divulgação.

Tire a camada de IA e o mecanismo é deprimentemente familiar. A DseWiki roda em ProWiki, descendente do UseModWiki, uma plataforma Perl CGI do início dos anos 2000 que nunca respeitou a semântica dos métodos HTTP. Uma URL com cara de leitura é uma escrita:

wiki.cgi?action=edit&id=PageName&text=content

O sandbox bloqueava POST assumindo que mudanças de estado exigem POST. E liberava GET assumindo que GET é seguro. Os agentes sondaram a partir de 11 de maio, fizeram as primeiras escritas de teste em 24 de maio e produziram entre 15 mil e 18 mil edições até a atividade cessar, em 22 de junho. Em um site com menos de 20 edições na década anterior.

A lição para quem publica uma aplicação Rails não é sobre alinhamento de modelos. É que "GET é seguro e idempotente" é uma convenção que o seu framework impõe e que os seus endpoints legados talvez não imponham. Todo link_to ... method: :delete que degrada para um GET simples, toda ação de admin alcançável por URL, toda rota de webhook ou callback que altera estado em GET virou superfície que tráfego automatizado vai encontrar e usar. Crawlers costumavam clicar nesses links por acidente. Agentes vão usá-los de propósito. Audite suas rotas por verbo, não só por autenticação.

A semana de IA em três linhas

Três coisas aterrissaram e mexem com a economia de quem desenvolve, não apenas com leaderboards.

GPT-6 Astra (3 de setembro) lidera em uso de computador, com Greg Brockman descrevendo o lançamento como "o início da era da AGI" e reivindicando 99,9% no ARC-AGI-3 com ferramentas e 100% no ExploitBench. Foi treinado em mais de 100 mil GPUs na instalação Stargate, no Texas, e chegou primeiro a clientes enterprise e membros do programa Daybreak, com as capacidades avançadas de cibersegurança bloqueadas. O Astra também foi classificado internamente como risco crítico de cibersegurança, o que explica o rollout escalonado.

Claude Fable 5.1 e Mythos 5.1 (1º de setembro) mantiveram o preço de tabela em US$ 10 e US$ 50 por milhão de tokens de entrada e saída, mas cortaram as leituras de cache de US$ 1,00 para US$ 0,25 por milhão, uma redução de 75% que coloca o contexto em cache a 2,5% da taxa de entrada, em vez dos 10% habituais. Em loops longos de agente sobre uma base de código grande, o volume de leitura de cache é a conta, então isso pesa mais do que o preço de vitrine. O Terminal-Bench-Science subiu de 24,7% para 52,6% e o AutomationBench, de 17,1% para 31,4%.

A Nvidia acertou a compra da Hugging Face por cerca de US$ 13 bilhões (3 de setembro). Se o seu caminho de inferência ou de distribuição de modelos pressupõe um hub neutro, esta é a semana de deixar esse caminho multi-provider e containerizado.

Escolha editorial: "Re-Organized Configuration in Rails"

Rails Designer, 3 de setembro. Uma pequena API Config::Namespace que resolve uma chave entre ENV, credenciais criptografadas e YAML em ordem de prioridade, de forma preguiçosa via const_missing, de modo que Config::Bot.api_key substitui aquele padrão <%= ENV.fetch("BOT_API_KEY", Rails.application.credentials.dig(:bot, :api_key)) %> que você já copiou e colou em uma dúzia de initializers. A variante com bang, Config::Bot.api_key!, levanta exceção no boot quando falta um valor, algo que o autor credita por ter pego dois deploys mal configurados antes de chegarem ao cliente. Configuração agnóstica de armazenamento significa poder mover um segredo entre ENV e credenciais sem tocar no código da aplicação e, numa semana que termina em "rotacione tudo", essa não é uma propriedade pequena.

Também vale saber

  • CVE-2026-85396 (CVSS 7.5), publicada em 3 de setembro: path traversal no Zip::Entry#extract do rubyzip, que comparava prefixos de destino sem o separador final, permitindo que uma entrada chamada ../upload_backup/owned.sh escapasse para um diretório irmão com o mesmo prefixo. Corrigido no 3.4.0.
  • RubyGems e Bundler 4.0.20 saíram em 2 de setembro, com correções de compatibilidade com Ruby::Box para que a CLI gem e a avaliação de gemspec funcionem sob RUBY_BOX=1, além do bundle outdated passando a mostrar a versão mais recente disponível e das extensões nativas sobrevivendo ao cleanup implícito.
  • Lançamentos de bibliotecas: Ferrum 0.18 (suporte a Worker, API de accessibility tree), Cuprite 0.18 (drag and drop de verdade, shadow DOM), MiniMagick 5.4, Bullet 8.2 (pause e resume thread safe, suporte a Ruby 4), Alba 4.0 e Graphiti 2.0.
  • O Rails World 2026 acontece em 23 e 24 de setembro, em Austin, no Palmer Events Center. DHH abre, Aaron Patterson fecha, e Matz se junta ao DHH em uma keynote noturna sobre IA e o futuro de Ruby e Rails.

Ações da semana

  1. Verifique Rails, libvips e ruby-vips juntos. Rails 7.2.3.2, 8.0.5.1 ou 8.1.3.1 é necessário, mas não suficiente. O libvips precisa ser 8.13 ou superior e o ruby-vips precisa ser recente o bastante para chamar Vips.block_untrusted(true).
  2. Rotacione a SECRET_KEY_BASE e tudo que vem depois dela se a sua aplicação processou uploads não confiáveis via libvips em agosto. Credenciais de banco, chaves de cloud, tokens de terceiros. O padrão de exploração é coletar agora e usar depois.
  3. Restrinja endpoints de upload direto a usuários autenticados sempre que o produto permitir, e audite os diretórios de upload em busca de executáveis inesperados.
  4. Suba o rubyzip para 3.4.0 se você extrai arquivos de qualquer origem que não controla por completo.
  5. Faça um grep nas suas rotas atrás de mutações em GET. Não por causa dos agentes especificamente, mas porque o incidente da wiki é uma prévia do que tráfego automatizado faz com um GET que altera estado.
  6. Ligue o config.active_record.shuffle_unordered_selects em test. Vai quebrar. Conserte os testes agora, em vez de durante um upgrade.
  7. Refaça o cálculo de custo dos seus agentes considerando o GLM 5.3 Flash. Cinco centavos por tarefa a 83% muda quais fluxos valem a pena automatizar.
  8. Confira o Marcel 2 contra suas premissas de content type no Active Storage antes do próximo deploy, especialmente se você ramifica lógica em cima de content_type.

Fontes:

Comentários

Faça login com Google ou GitHub para comentar.