[CVE-2026-66066] Attack details, and tools to perform a forensic investigation

Hello there, I’m writing as a member of the Rails security team about CVE-2026-66066.

As mentioned in the advisory, GHSA-xr9x-r78c-5hrm, we held back details about the attack vector to allow applications to be upgraded before malicious attackers could take advantage of the vulnerability.

We originally intended to publish these details no later than 2026-08-28, but several researchers quickly reverse-engineered the attack and have already published proofs-of-concept. As a result, we are disclosing details about the attack now, along with some tools to help assess whether an application was vulnerable and to help examine the forensic evidence for signs of secret exfiltration.

We have published all of this in a git repository, rails/rails-forensics-CVE-2026-66066, which contains:

  • reference/the-attack.md explains how the attack works, step by step, from the incoming request to the file being read.
  • reference/the-investigation.md explains what evidence the attack leaves behind in your database and your object store, and what that evidence does and does not prove.
  • The kr2s-was-i-vulnerable agent skill works out whether your application was ever vulnerable, and if it was, over what period of time.
  • The kr2s-was-i-exploited agent skill searches your Active Storage data for the crafted files, and works out what was read if it finds any.

I sincerely hope you find this information and these tools helpful. They were extracted from work I did at 37signals to perform a forensic analysis on our own apps. And if you have suggestions on how to improve it, I would welcome pull requests that are likely to be generally useful.

We again want to thank the original reporters, 0xacb, s3np41k1r1t0 and castilho of Ethiack, and RyotaK of GMO Flatt Security Inc., for responsibly reporting this vulnerability and for holding off on publishing attack details at our request.

2 Likes

We have also noticed an increase in this style of attack at Discourse.

We use ImageMagick at the moment with a list of allowed coders, but are porting over to vips.

An important defence in depth we introduced this week was:

Coupled with Discourse changes to lean on SafeExec.

The defence in depth strategy we opted for is to stop running image processing libraries in processes that have high levels of permission. Landlock, unlike namespace based techniques (such as bubblewrap), needs no privileges or nested user namespaces, so it is container friendly and rolling this out is significantly simpler. That said landlock is an evolving set of capabilities in the Linux kernel and prior to ABI 5 (Linux 6.10) there are real filesystem gaps (device ioctls land in ABI 5, truncate in ABI 3, rename/link in ABI 2)

The landlock gem provides a series of things that guard a process, from easy, to more complicated:

  1. ENV scrubbing
  2. Resource limits via rlimits
  3. Timeouts to stop rogue processes
  4. Process groups to ensure proper teardown
  5. Seccomp profile to deny network access (UDP prior to ABI 10 can not be blocked via landlock)
  6. Landlock dynamic policy depending on Kernel

It also fails closed: capture refuses to run with an empty policy and raises rather than silently running a command unsandboxed.

Given our landlock requirement now, our move to vips is going to require calling the vips binary direct vs leaning on the Ruby gem. That said, now that we have ImageMagick in a box we are a lot less stressed.

On a fundamental level both landlock and seccomp profiles let you restrict what a process can do (what files it can see, what syscalls it can make) once ratcheted down you can’t ratchet it back up, and the restrictions are inherited by the calling thread and all its future children. (Sibling threads are only covered from ABI 8, via the TSYNC flag.)

Now this style of protection does not give you immunity to RCE forever, but it does heavily restrict the risk profile, when an image library is resizing an image … it only needs to write to 1 spot not have global write to the entire filesystem. Similarly it has no reason to be allowed to talk to your database or run forever.

LLMs are getting pretty scary cyber capabilities today, so sadly the reality is that it is a countdown till the next buffer overflow in libvips or any of the libraries it delegates to. Scary times that call for defence in depth.

6 Likes