Rails Held the Exploit Details Until August 28. A Working PoC Was on GitHub the Same Day.
- Patrick Duggan
- 1 hour ago
- 4 min read
Ruby on Rails published the advisory for CVE-2026-66066 on July 29. Arbitrary file read in Active Storage, CVSS 9.5, no authentication required, reachable through any application that accepts an image upload from an untrusted user. Because the file it reads includes the Rails process environment, and because that environment holds SECRET_KEY_BASE, the read becomes code execution.
The Rails security team did the responsible thing and withheld the technical detail. Their stated plan was to publish the mechanics on August 28 — thirty days of quiet for operators to patch before anyone had a recipe.
Our exploit harvester indexed a public proof-of-concept repository for it at 00:00:52 UTC on July 30. The repository, Zer0SumGam3/CVE-2026-66066-POC, was created at 21:08:30 UTC on July 29. Same calendar day as the advisory.
The embargo did not last thirty days. It did not last one.
What the embargo actually bought
We want to be careful here, because the instinct is to read this as the Rails team having failed. They did not. The advisory was coordinated, fixes shipped alongside it, affected version ranges were precise, and the decision to hold details is the decision we would want any maintainer to make.
What failed is the assumption underneath the decision — that withholding the write-up meaningfully delays the exploit. It does not, and it has not for some time. A CVSS 9.5 with a named component, a named library, and a patch diff is not a mystery. It is a puzzle with the answer sitting in a public commit. Anyone competent who wants the mechanics can read the fix and work backwards, and on a bug this valuable, somebody always wants to.
So the thirty-day window was never a window. The real interval between disclosure and public weaponisation, measured on our own instruments, was somewhere under twelve hours. Everything an operator planned to do "before the details drop" needed to already be done.
This is not a Rails-specific finding. It is the pattern we keep measuring across the KEV corpus — the gap between an advisory and a working script is now short enough that treating a coordinated embargo as breathing room is a planning error. Patch on the advisory, not on the schedule the advisory promises.
The bug, plainly
Active Storage generates image variants. Since Rails 7.0 defaults, the processor doing that work is libvips. The vulnerability is that Active Storage allowed unsafe libvips operations to run against attacker-controlled uploads.
That means a crafted file, uploaded through a perfectly ordinary avatar or attachment form, can cause the image pipeline to read files it has no business reading and return their contents back through the variant. What gets read is whatever the Rails process can read. In a normal deployment that includes the environment, and the environment includes the key that signs your sessions and your Marshal payloads. From a signed payload to remote code execution is a well-worn path in Rails.
The public PoC our harvester picked up chains exactly that. The detection rules we extracted from it point at a shell invocation as the terminal stage. It is not a theoretical read primitive; it is the whole ladder.
Credit where it belongs: this was independently reported by researchers at Ethiack, who named their write-up KindaRails2Shell, and by GMO Flatt Security. Two teams finding the same bug independently is itself a signal about how discoverable it was.
What to do tonight
Patch. Active Storage below 7.2.3.2 is affected, 8.0 through 8.0.5.0 is affected, 8.1 through 8.1.3.0 is affected. Go to 7.2.3.2, 8.0.5.1, or 8.1.3.1. Rails 6.x is only affected where somebody manually enabled the vips processor, which is rare but worth checking rather than assuming.
Confirm libvips is 8.13 or newer while you are in there.
Then rotate. This is the part people will skip and should not. The vulnerability's payoff is reading secrets, the window has been open since the advisory landed and arguably longer, and you have no logging that would distinguish a malicious variant generation from a legitimate one. If your application accepted image uploads from untrusted users on an affected version, treat every secret that process could read as exposed: SECRET_KEY_BASE first, then database credentials, then any API key in the environment. Rotating a key you did not need to rotate costs an afternoon. The alternative costs considerably more and you find out about it later.
If you genuinely cannot patch tonight, stop accepting image uploads from unauthenticated users. That is a worse answer than patching and it is the only other one that touches the actual attack path.
The honest position
We did not find this bug and we are not claiming a lead on it. Ethiack and GMO Flatt Security found it, Rails fixed it, and we read the advisory like everyone else.
What we hold is a timestamp, and it is ours: our harvester runs on its own schedule against public repositories and recorded the proof-of-concept appearing at 00:00:52 UTC on July 30, against a repository created at 21:08:30 UTC on July 29. That is a first-party observation from our own instrumentation, not an ingest of somebody else's research, and it is the specific thing we can tell you that the advisory cannot: the thirty days you were promised were about twelve hours.
Confidence capped at 95%. Version ranges and severity come from the Rails advisory and the CVE record. The repository timestamps are GitHub's, as read by our harvester. The claim that no earlier public PoC existed is a point-in-time observation from our corpus and is designed to expire — if an earlier one surfaces, this post is wrong about the interval and right about the lesson.
Every indicator in this post is in the feed. Free.
1.58M+ IOCs, STIX 2.1 / TAXII, 88% novel vs ThreatFox, exploited-CVE leads ahead of CISA. No credit card — a free API key in 30 seconds, and you can audit every claim above against the live endpoints.
