CVE-2026-66066, called KindaRails2Shell, lets an unauthenticated attacker who can upload an image read arbitrary files from a Rails server. CVSS 9.5. Found by Ethiack.
Arbitrary file read on a Rails box means secret_key_base, the master key, database passwords, cloud storage credentials and API tokens — which is why the write-ups end at remote code execution rather than at disclosure.
The bug is a disagreement between two libraries
Per Rapid7's analysis, the flaw sits between libvips and libmatio, and neither is wrong on its own.
- libvips decides whether a file is a MATLAB file by reading bytes 0–9 and looking for the string
MATLAB 5.0. - libmatio, which actually parses it, reads the version identifier at bytes 124–125.
So an attacker crafts one file that says MATLAB 5.0 at the front and carries MAT 7.3 version markers further in, plus an HDF5 external-storage reference pointing at any path on disk. libvips accepts it. libmatio parses it as MAT 7.3, follows the external dataset pointer, and reads the file the attacker named.
Two correct parsers, two different answers to "what is this file", and the gap between them is the vulnerability. It is the same shape as every content-type confusion bug, which is worth remembering the next time a design has one component sniff a file and a different component parse it.
The part that is being reported wrong
Some coverage of this frames the patch as leaving a gap.
Rapid7 does not say that. The patch blocks the file read: it requires libvips 8.13+ and ruby-vips 2.2.1+, then calls Vips.block_untrusted(true) at initialisation, after which — in Rapid7's words — libvips skips the matload operation "before the crafted file can reach libmatio". Rapid7 reproduced the full chain against unpatched 6.0.6.1, 6.1.7.10, 7.2.3.1, 8.0.5 and 8.1.3, wrote a Metasploit module for it, and reports that patched targets block the crafted representation.
The RCE gadget people are pointing at is a separate chain, and it is not what this CVE is.
The real caveat is a dependency, not a gap
Read that fix mechanism again, because it has an operational consequence that has been almost entirely lost.
The Rails patch does not fix the parser confusion. It asks libvips to refuse untrusted operations — and that call only does anything on libvips 8.13 or newer with ruby-vips 2.2.1 or newer.
Which means: bundle update is not the whole remediation. The gem version is what your dependency scanner reads and what your compliance report will show as green. The thing that actually blocks the attack is a native system library, installed by your base image or your distribution, that no Gemfile.lock records.
If your Dockerfile pins an older base image, or your hosts run a long-term-support distribution with an older libvips, you can be fully patched by every measure your tooling understands and still be reachable.
Check the library, not just the gem.
Versions
Affected Active Storage, per Rapid7:
- Below 7.2.3.2
- 8.0 up to but not including 8.0.5.1
- 8.1 up to but not including 8.1.3.1
Patched in 7.2.3.2, 8.0.5.1 and 8.1.3.1.
The precondition is Active Storage using libvips for image processing on uploads you do not control. An application that accepts avatars from the internet qualifies.
Exploitation
VulnCheck reported exploitation beginning around a month after the patches shipped: more than 50 detections within hours on 30 August, and more than 360 by the following Monday. A France-based IP was seen driving CVE-2026-66066 specifically, with command-and-control infrastructure in Israel and targets in the UK and Singapore. We have this second-hand — through reporting of VulnCheck's findings rather than from a VulnCheck write-up we could read directly — and have not independently verified the counts.
Two exposure figures are circulating and they measure different things. Ethiack's disclosure has been reported as affecting more than 500,000 sites; VulnCheck counted 7,100+ internet-exposed Rails instances in early August. Neither is a count of exploitable hosts — the first is a population, the second is what one scanner could see.
What to do
- Upgrade Active Storage to 7.2.3.2, 8.0.5.1 or 8.1.3.1.
- Then check libvips and ruby-vips versions on the running host, not in the lockfile. Below libvips 8.13 or ruby-vips 2.2.1, the fix is inert.
- Rotate
secret_key_base, the master key, database credentials and any cloud tokens if the application was internet-facing and unpatched for any of the last month. File read is silent; assume it happened rather than looking for proof it did not. - Check
/proc/self/environand your config files against what an attacker would have found there. - Stop accepting arbitrary uploads into an image pipeline that then sniffs the format. Decide the format at the boundary, from something you control.
What is not established
- Whether any of the observed exploitation succeeded. Detections are attempts.
- Overlap between the France-based activity and any known group. Not attributed.
- How the 500,000 figure was derived, or what it counts.
- Whether the RCE gadget is reachable on a patched host by another route. Rapid7 describes it as depending on a separate gap; nobody has demonstrated the combination post-patch.