
A critical flaw in Ruby on Rails Active Storage — CVE-2026-66066, nicknamed KindaRails2Shell — lets unauthenticated attackers upload a crafted file, read arbitrary files off your server, steal your secret_key_base, and chain that into remote code execution. The flaw affects Rails 7.0 through 8.1.3 when using libvips (the default image processor since Rails 7.0), exploit code has been public since July 31, and a Metasploit module now automates the full chain. If you run a Rails app that accepts file uploads, you have three things to do right now: upgrade Rails, update libvips, and rotate every secret your app can access.
How KindaRails2Shell Works
libvips, the high-performance image library Rails 7.0 made its default, supports an unusual range of file formats beyond standard images — PDFs, SVGs, MATLAB .mat files, NIfTI medical scans, astronomical FITS files. Many of these loaders are flagged internally as “unfuzzed,” meaning they were never hardened for untrusted content. libvips provides a kill switch — VIPS_BLOCK_UNTRUSTED=true — to disable them. Active Storage never sets it.
The exploit uses that gap. An attacker uploads a MATLAB v7.3 file (an HDF5 container) through the unauthenticated direct upload endpoint that Rails exposes by default. The file embeds an arbitrary path reference. When Active Storage triggers variant generation, libvips passes the file to libmatio, which follows the embedded path and reads whatever file is there — /proc/1/environ, Rails credentials, cloud keys. Once the attacker has secret_key_base, they sign a malicious ImageProcessing variation containing a send/spawn payload, submit it, and get a shell. Rapid7’s analysis shows the full chain running in a single automated workflow.
The name “KindaRails2Shell” captures it well: no direct shell from the file read. It’s indirect, multi-hop, and now fully scripted.
Who’s Exposed
The exposure is wider than it looks. libvips became the Rails default in 7.0, released in 2021. That’s five years of Rails apps running the vulnerable configuration out of the box. An application is at risk if it uses Active Storage with libvips, accepts uploads from untrusted users, and runs any Rails version from 7.0.0 through 8.1.3. Ethiack, who discovered the flaw, puts the number of affected sites above 500,000. The CVSSv4 score is 9.5.
What’s worth noting: the trigger is the unauthenticated direct upload endpoint, not just a public-facing file picker. If you built an internal tool assuming only authenticated users reach your upload forms, check again — the Rails direct upload route is separate, and by default it requires no authentication.
Three Steps, Not One
This is where teams are getting tripped up. Patching means three things, and doing only one or two leaves you exposed.
Step 1: Upgrade Rails. The fixed versions are 7.2.3.2, 8.0.5.1, and 8.1.3.1. Update your Gemfile and run bundle update rails activestorage.
Step 2: Update libvips to 8.13 or newer. Rails 8.1.3.1 ships the fix in the gem layer, but older libvips builds won’t honor the new block calls. Run vips --version to check. On Ubuntu/Debian: apt update && apt install libvips-dev. On macOS: brew upgrade vips. On Docker: verify your base image and rebuild.
Step 3: Rotate your secrets. Every secret the Rails process could read during the exposure window is compromised — assume it. That means secret_key_base, database credentials, AWS/GCP/Azure keys, third-party API tokens. Patching Rails does not revoke credentials that already leaked.
According to Bleeping Computer’s coverage, teams that patched Rails on July 29 but haven’t rotated secrets remain exposed to the PoC that dropped July 31. The two-day window between patch and public exploit is exactly the trap.
Can’t Patch Right Now?
If you’re blocked on patching — frozen deploys, regulatory hold, or simply need an hour — there’s a partial workaround for libvips 8.13+. Add this to an initializer:
# config/initializers/vips_security.rb
Vips.block_untrusted(true) if Vips.respond_to?(:block_untrusted)
Or set VIPS_BLOCK_UNTRUSTED=true before the process starts. This disables the dangerous loaders at the libvips level. It does not work on libvips older than 8.13. Akamai’s defense analysis covers WAF rules they published, but be clear-eyed about what WAF rules do: they add noise to an attacker’s session, they do not revoke a secret that already left your server.
Check If You Were Already Hit
The Rails team published a forensic toolkit at github.com/rails/rails-forensics-CVE-2026-66066. It runs two checks: one determines whether you were ever in the vulnerable window, another searches Active Storage for crafted files. Run it. But understand the limits: finding no crafted file doesn’t clear you. Attackers may have deleted evidence, hit a staging environment, or used an alternate upload path not captured in your primary data store. Cross-reference the output with access logs, cloud storage logs, and unusual sessions or database queries during the exposure window.
Bottom Line
KindaRails2Shell is dangerous not because the attack is clever — the file-read-to-shell chain has precedent — but because libvips is the Rails default and the attack is now fully automated. You’re not protecting against a sophisticated attacker; you’re protecting against a script that runs against every exposed Rails app it can find. Upgrade Rails, update libvips, rotate secrets. All three. In that order.













