
rails-activestorage-vips-audit — Updated!
Habilidade de agente que audita uma base de código Rails para a CVE-2026-66066 (KindaRails2Shell) — leitura arbitrária de arquivos / RCE no Active Storage + libvips, verificando versões do Rails e do libvips e mitigações de block-untrusted.
rails-activestorage-vips-audit
Uma Agent Skill que audita repositórios Ruby on Rails quanto à exposição a CVE-2026-66066 (KindaRails2Shell) — a vulnerabilidade do Active Storage de processamento de variantes com libvips que permite leitura arbitrária de arquivos e, em uma aplicação Rails, execução remota de código.
A skill é um auditor de configuração e um auxílio de remediação. Ela não contém código de exploit e não descreve a cadeia de ataque.
A vulnerabilidade
| CVE | CVE-2026-66066 |
| Gravidade | Crítica, CVSS 9.5 |
| Pacote | activestorage (RubyGems) |
| Afetadas | < 7.2.3.2, >= 8.0 < 8.0.5.1, >= 8.1 < 8.1.3.1 |
| Corrigidas | 7.2.3.2, 8.0.5.1, 8.1.3.1 |
| Aviso | GHSA-xr9x-r78c-5hrm |
O libvips lê e grava formatos por meio de operações, algumas das quais ele marca como unfuzzed — inseguras para conteúdo não confiável. O Active Storage não as desabilitava, então um atacante que consiga enviar um arquivo manipulado pode alcançá-las.
Uma aplicação está exposta somente quando todas as quatro condições são verdadeiras:
activestorageestá em uma faixa de versão afetada- O Active Storage está em uso
config.active_storage.variant_processorresolve para:vips- A aplicação aceita uploads de usuários não confiáveis
A condição 3 é a discriminante. A faixa afetada < 7.2.3.2 inclui todas as versões Rails 6.x, mas o 6.x usa :mini_magick por padrão, portanto o 6.x está exposto somente sob uma configuração não padrão, e versões anteriores à 6.0 não possuem configuração variant_processor alguma. O Rails 7.0 e posteriores usam :vips por padrão via config.load_defaults 7.0, motivo pelo qual a configuração comum está exposta. O Rails 8.1 também aceita :disabled, o que torna a condição 3 falsa.
Instalação
Como plugin do Claude Code, por meio do marketplace incluído neste repositório:
/plugin marketplace add paveg/rails-activestorage-vips-audit
/plugin install rails-activestorage-vips-audit@paveg-skills
Com a CLI skills, que instala a mesma skill no Claude Code, Codex, Cursor, Copilot CLI e outros agentes:
npx skills add paveg/rails-activestorage-vips-audit
Ou manualmente:
git clone https://github.com/paveg/rails-activestorage-vips-audit.git
cp -r rails-activestorage-vips-audit/skills/rails-activestorage-vips-audit ~/.claude/skills/
~/.agents/skills/ funciona como um local entre runtimes para Codex, Copilot CLI e Gemini CLI. Nada na skill depende de onde ela está instalada — não há caminhos absolutos, e collect-evidence.sh resolve tudo em relação à raiz da aplicação para a qual é apontado.
Uso
A skill tem dois modos, e ambos aceitam múltiplos caminhos de aplicação.
report <app>... # read-only audit, one verdict per application
fix <app>... # applies remediation on a branch; never commits or pushes unprompted
Instalada como plugin, cada modo também é um comando, portanto o modo não precisa ser digitado como argumento:
/rails-activestorage-vips-audit:report path/to/app another/app
/rails-activestorage-vips-audit:fix path/to/app
Os comandos são pontos de entrada para você, não para o agente: eles são marcados para que o Claude nunca os acione por conta própria. O Claude ainda invoca a skill em si quando uma solicitação corresponde a ela, por isso fix não pode ser iniciado sem que um humano o solicite.
report é o padrão. fix exige antes um veredito de report para a mesma aplicação, pois a remediação correta depende dele — Rails 6.x, 7.0.x e 7.1.x não possuem correção na mesma série, então nesses casos fix aplica a mitigação provisória e informa que uma atualização do framework é necessária, em vez de tentar fazê-la.
A coleta de evidências também pode ser executada de forma isolada:
skills/rails-activestorage-vips-audit/scripts/collect-evidence.sh path/to/app another/app
O script coleta fatos e, deliberadamente, não contém lógica de veredito. Passe a raiz de uma aplicação, não a raiz indiferenciada de um monorepo. Para um monorepo, passe cada diretório Rails implantável com seu próprio Gemfile.lock e config/application.rb como um argumento separado. O coletor exclui essas raízes de aplicação aninhadas do fluxo de evidências de um pai, mantendo raízes de lockfile aninhadas que podem ser engines montadas ou path dependencies.
O que ela não lhe dirá
- A versão do libvips em tempo de execução. Ela não pode ser determinada de forma conclusiva a partir de um repositório, e isso importa: abaixo do libvips 8.13, as operações inseguras não podem ser desabilitadas de forma alguma. Em uma aplicação sem correção, isso significa que nenhuma mitigação pode funcionar; em uma corrigida, significa que o Active Storage gera erro na inicialização em vez de executar sem segurança, então uma atualização não verificada faz o deploy falhar em vez de deixar um buraco silencioso. Verifique com
vips --versiononde a aplicação é executada. Os relatórios mantêm isso em prontidão de runtime e remediação, em vez de tornar o veredito de exposição condicional. - Se uma mitigação está ativa.
VIPS_BLOCK_UNTRUSTEDem um Dockerfile não prova que o ambiente implantado a define. A skill limita tais constatações a "mitigação provisória presente, atualização ainda necessária" e nunca permite que uma delas produza um veredito limpo.
Resumo da remediação
Atualize para 7.2.3.2, 8.0.5.1 ou 8.1.3.1, de acordo com a sua série. Confirme o libvips de runtime >= 8.13 e ruby-vips >= 2.2.1 primeiro: onde ruby-vips está instalado, o Active Storage corrigido gera erro na inicialização a menos que ambos sejam atendidos, e essa verificação também se aplica a aplicações :mini_magick.
Mitigações provisórias, nenhuma das quais substitui a atualização:
- Defina a variável de ambiente
VIPS_BLOCK_UNTRUSTED(libvips>= 8.13; nenhuma alteração de gem necessária) - Chame
Vips.block_untrusted(true)a partir de um initializer (ruby-vips >= 2.2.1, além de libvips>= 8.13)
Em ruby-vips < 2.2.1, o caminho do initializer chama um método que ainda não existe; portanto, atualize a gem primeiro ou use o caminho da variável de ambiente, que não depende dela.
Se uma aplicação esteve exposta, considere todo segredo legível pelo processo da aplicação como comprometido e faça a rotação: secret_key_base, a master key, credenciais do serviço do Active Storage, credenciais do banco de dados e tokens de terceiros.
Um WAF não é uma mitigação aqui. Se ele consegue ver o payload depende do serviço de armazenamento e do método de upload, portanto sua eficácia depende demais da configuração para que se possa confiar nela.
Aviso legal
- Use esta skill somente em repositórios que você possua ou para os quais esteja explicitamente autorizado a auditar.
- Vereditos são análises estáticas de melhor esforço. Um veredito NOT AFFECTED não é prova de não exposição: variáveis de ambiente implantadas e código em outros serviços são invisíveis para uma auditoria de repositório. O libvips de runtime é relatado separadamente porque afeta a mitigação e a prontidão de implantação, não se o repositório atende às condições de exposição.
- A skill não contém código de exploit e não reconstruirá a cadeia de ataque, independentemente de como uma solicitação for formulada.
- Fornecida sob a Licença MIT, sem garantia de qualquer tipo. Agir com base em um relatório — atualizações, mitigações, rotação de segredos — continua sendo responsabilidade do operador.
Fontes
- Aviso de segurança do Rails GHSA-xr9x-r78c-5hrm
- Ethiack — KindaRails2Shell: Rails RCE (CVE-2026-66066)
- Guias do Rails — Configuring Rails Applications
A vulnerabilidade foi encontrada e relatada de forma independente por RyotaK da GMO Flatt Security e por uma equipe da Ethiack composta por André Baptista, Bruno Mendes e Castilho, e foi divulgada em coordenação com os mantenedores do Rails.