---
schema: 1
kind: vulnerability
title: >
  CVE-2026-66066 — Ruby on Rails Active Storage: an unauthenticated image upload reaches arbitrary
  file read through libvips' unfuzzed loaders, exposing every application secret (CVSS 4.0 9.5)
headline: >
  Rails patches a default-configuration flaw where accepting an image upload is enough to read the
  application's secrets
summary: >
  Rails shipped fixes on 2026-07-29 for CVE-2026-66066 ("KindaRails2Shell"), a critical flaw in
  Active Storage's image-variant processing on libvips — the default variant processor since Rails
  7.0. libvips marks some format loaders "unfuzzed" and unsafe for untrusted content, and Active
  Storage never disabled them, so an unauthenticated attacker who can upload an image to any Rails
  application reaches arbitrary file read as the application process, including secret_key_base
  and decrypted credentials. Fixed in activestorage 7.2.3.2, 8.0.5.1 and 8.1.3.1, but only in
  combination with libvips 8.13 or newer — a patched gem on older libvips cannot protect itself
  and refuses to boot. No exploitation is reported and the discoverers are withholding the chain
  until 2026-08-28, while warning that the patch diffs make reconstruction fast.
discovered_at: "2026-07-31T04:09:14Z"
updated_at: "2026-08-10T04:54:00Z"
event_date: 2026-07-29
run_id: 2026-07-31T0409Z-intel
priority: high
immediate_action: null
tags:
  - vulnerabilities
  - rce
  - pre-auth
  - default-config
  - info-disclosure
  - patch-available
  - poc-public
regions:
  - global
  - europe
sectors:
  - public-sector
  - technology
  - finance
  - healthcare
entities: []
techniques:
  - T1190
  - T1005
  - T1552
  - T1552.001
affected_products:
  - Ruby on Rails Active Storage
  - libvips
  - ruby-vips
  - Ruby on Rails
cves:
  - id: CVE-2026-66066
    cvss: "9.5"
    epss: null
    type: path-traversal
    vector: zero-click
    auth: pre-auth
    status:
      - poc-public
      - patch-available
    affected: "< 7.2.3.2, >= 8.0 < 8.0.5.1, >= 8.1 < 8.1.3.1"
    fixed: "7.2.3.2, 8.0.5.1, 8.1.3.1"
sources:
  - url: "https://discuss.rubyonrails.org/t/cve-2026-66066-possible-arbitrary-file-read-and-remote-code-execution-in-active-storage-variant-processing/91432"
    publisher: Ruby on Rails security advisory
    date: 2026-07-29
    role: primary
  - url: "https://ethiack.com/info-hub/research/kindarails2shell-rails-rce-cve"
    publisher: Ethiack
    date: 2026-07-29
    role: primary
  - url: "https://www.rapid7.com/blog/post/etr-kindarails2shell-cve-2026-66066-critical-arbitrary-file-read-and-possible-remote-code-execution-in-ruby-on-rails"
    publisher: Rapid7
    date: 2026-07-30
    role: primary
  - url: "https://www.cert.ssi.gouv.fr/avis/CERTFR-2026-AVI-0948/"
    publisher: CERT-FR / ANSSI
    date: 2026-07-30
    role: corroborating
  - url: "https://discuss.rubyonrails.org/t/cve-2026-66066-attack-details-and-tools-to-perform-a-forensic-investigation/91441"
    publisher: Ruby on Rails security team
    date: 2026-07-31
    role: primary
  - url: "https://github.com/rails/rails/security/advisories/GHSA-xr9x-r78c-5hrm"
    publisher: Ruby on Rails security advisory (GHSA)
    date: 2026-07-29
    role: corroborating
  - url: "https://www.rapid7.com/blog/post/ra-kindarails2shell-technical-analysis-cve-2026-66066"
    publisher: Rapid7
    date: 2026-08-03
    role: primary
  - url: "https://www.rapid7.com/blog/post/etr-kindarails2shell-cve-2026-66066-critical-arbitrary-file-read-and-possible-remote-code-execution-in-ruby-on-rails/"
    publisher: Rapid7
    date: 2026-07-30
    role: corroborating
closed_sources: []
evidence:
  - quote: "An application is affected if it meets all of these requirements: Uses libvips for Active Storage image processing. This is config.active_storage.variant_processor = :vips, which load_defaults 7.0 set and no later default has changed. Allows image uploads from untrusted users. Generating variants is not a separate requirement."
    publisher: Ruby on Rails security advisory
  - quote: "Earlier versions of libvips (< 8.13) cannot disable unfuzzed operations at all, and Active Storage will raise an exception during boot in such an unsecurable environment."
    publisher: Ruby on Rails security advisory
  - quote: "No PoC or technical chain details from us yet, but assume attackers with AI tooling can reconstruct one quickly once patches ship and diffs go public, so don't wait to upgrade."
    publisher: Ethiack
  - quote: we held back details about the attack vector to allow applications to be upgraded before malicious attackers could take advantage of the vulnerability.
    publisher: Ruby on Rails security team
  - quote: "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."
    publisher: Ruby on Rails security team
  - quote: "As of July 30, 2026, Rapid7 is not aware of exploitation in the wild."
    publisher: Rapid7
  - quote: "We reproduced the published chain against Rails 6.0.6.1, 6.1.7.10, 7.2.3.1, 8.0.5, and 8.1.3, and confirmed that patched 7.2.3.2, 8.0.5.1, and 8.1.3.1 targets block the crafted representation."
    publisher: Rapid7
  - quote: "This RCE path does not depend on a Marshal object gadget. We validated it against Rails 8.0.5 configured with config.active_support.message_serializer = :json."
    publisher: Rapid7
verification: multi-source
sourcing_note: >
  Version ranges and preconditions are taken from the Rails advisory's own structured data rather
  than any prose roundup. One widely-repeated detail does not come from the Rails advisory at all:
  the claim that Rails 6.x may be affected is Ethiack's separate researcher assessment, relayed by
  Rapid7 with attribution, and neither the advisory's own affected-version ranges nor the CVE
  record list any 6.x range — the entry attributes it accordingly. The CVSS 4.0 score of 9.5 was
  assigned by GitHub Security Advisories acting as the Rails CNA and is reported rather than
  independently derived by Rapid7; CERT-FR's advisory carries no score at all.
confidence: high
references: []
deep_dive: false
deep_dive_category: null
org_triage: null
classification:
  reliability: A
  credibility: 1
watchlist_hit: false
actions:
  - "Upgrade activestorage to 7.2.3.2, 8.0.5.1 or 8.1.3.1 AND confirm the host's libvips is >= 8.13 — a patched gem on older libvips raises an exception at boot rather than protecting the application, so a failed start after upgrading is the expected signal, not a regression."
  - "Where libvips cannot be upgraded immediately, set VIPS_BLOCK_UNTRUSTED or call Vips.block_untrusted(true) from an initializer with ruby-vips >= 2.2.1 as an interim control on any Rails app accepting image uploads from untrusted users."
  - "Run the kr2s-was-i-vulnerable and kr2s-was-i-exploited agent skills from the rails/rails-forensics-CVE-2026-66066 repository against every Rails application configured with the libvips variant processor that accepted untrusted image uploads before it reached activestorage 7.2.3.2 / 8.0.5.1 / 8.1.3.1 on libvips >= 8.13, and for any application the exploited skill flags rotate secret_key_base, the master key and every credential reachable through credentials.yml.enc — storage and database credentials and third-party tokens included — because the patch does not invalidate a secret that was already read."
updates:
  - at: "2026-08-02T04:09:57Z"
    run_id: 2026-08-02T0409Z-intel
    type: update
    summary: >
      Rails had held back the exploitation details for CVE-2026-66066, the Active Storage
      arbitrary-file-read flaw, until no later than 2026-08-28. On 2026-07-31 the security team
      abandoned that embargo because researchers had already reverse-engineered the bug and published
      proofs-of-concept, and released a repository containing a step-by-step attack write-up, a
      forensic-evidence guide and two agent skills that determine whether an application was
      vulnerable and whether it was exploited. Any Rails application still on an unpatched
      activestorage that used the libvips variant processor and accepted image uploads from untrusted
      users is now exposed to a fully public chain, and the published forensic check is the way to
      find out whether its secrets were already read.
    fields:
      - actions
      - cves
      - evidence
      - sources
      - tags
      - techniques
      - body
    merged_from: 2026-08-02/cve-2026-66066-rails-attack-chain-public-forensic-tooling
  - at: "2026-08-10T04:54:00Z"
    run_id: 2026-08-10T0411Z-intel
    type: update
    summary: >
      Rapid7 published a full technical reproduction of the Rails Active Storage arbitrary-file-read
      chain on 2026-08-03 and released a Metasploit module implementing it. The module creates crafted
      direct-upload blobs, confirms the file read, recovers and validates Rails signing material, and
      triggers command or native Ruby payloads. Rapid7 validated the code-execution path against Rails
      8.0.5 configured with the JSON message serializer, so it does not depend on a Marshal
      deserialization gadget. The status change is weaponisation and automation, not attacker
      activity: Rapid7's own tracker states it is not aware of exploitation in the wild, and neither
      post claims observed scanning or intrusions.
    fields:
      - affected_products
      - cves
      - evidence
      - sources
      - body
    merged_from: 2026-08-10/cve-2026-66066-rapid7-metasploit-module-weaponisation
migrated_from: null
---

The Rails security team disclosed CVE-2026-66066 on 2026-07-29, nicknamed "KindaRails2Shell" by its finders, and CERT-FR carried it the following day ([CERT-FR, 2026-07-30](https://www.cert.ssi.gouv.fr/avis/CERTFR-2026-AVI-0948/)). The defect is one of insecure defaults rather than a memory-safety bug. libvips reads and writes image formats through loaders and savers, some of which it explicitly flags "unfuzzed" — meaning the project does not consider them safe against attacker-controlled input. Active Storage, which has used libvips as its default variant processor since Rails 7.0, never disabled those operations before handing it user-supplied files. A crafted upload therefore reaches an unfuzzed loader and yields arbitrary file read in the context of the application process ([Ruby on Rails security advisory, 2026-07-29](https://discuss.rubyonrails.org/t/cve-2026-66066-possible-arbitrary-file-read-and-remote-code-execution-in-active-storage-variant-processing/91432)).

The precondition set is narrower than "runs Rails" but wider than most operators will assume. The advisory states an application is affected if it uses libvips for Active Storage image processing — the default that `load_defaults 7.0` set and that no later default has changed — and accepts image uploads from untrusted users, and it says in as many words that generating a variant is *not* a separate requirement. Authentication elsewhere in the application does not help, because the exposure sits in the image-processing pipeline rather than the request-authorisation layer. Ethiack notes one further precondition it is not detailing yet — that the libvips build be linked against certain third-party libraries — so not every deployment on a vulnerable version is equally reachable, and it states that applications configured for the alternative ImageMagick processor are outside this vector entirely ([Ethiack, 2026-07-29](https://ethiack.com/info-hub/research/kindarails2shell-rails-rce-cve)).

The "possible remote code execution" in the CVE's title is a consequence rather than a direct primitive: file read as the application process exposes `secret_key_base`, the master key and everything `credentials.yml.enc` decrypts, storage and database credentials and third-party tokens, and those in turn open paths to code execution or to connected systems ([Rapid7, 2026-07-30](https://www.rapid7.com/blog/post/etr-kindarails2shell-cve-2026-66066-critical-arbitrary-file-read-and-possible-remote-code-execution-in-ruby-on-rails)). That is why remediation does not end at the upgrade — Rapid7 advises rotating `secret_key_base` and every credential the process can reach on any application believed exposed, while noting that rotating it invalidates active sessions, signed and encrypted cookies, signed global IDs and existing Active Storage URLs.

Fixed releases are activestorage 7.2.3.2, 8.0.5.1 and 8.1.3.1, and the advisory is unusually blunt that the gem upgrade alone is not the fix: libvips itself must be at 8.13 or newer, because earlier versions cannot disable unfuzzed operations at all, and patched Active Storage raises an exception at boot rather than running in a configuration it cannot secure. Separately, Ethiack assesses that Rails versions 6.0.0 through 6.1.7.10 may be affected where Active Storage has been configured for libvips against its own defaults, with no fixed 6.x release available — a point Rapid7 relays with attribution to Ethiack, and which does not appear in the Rails advisory's own affected-version ranges.

No in-the-wild exploitation was reported as of 2026-07-30, and both reporting teams — Ethiack and GMO Flatt Security, who found it independently — are withholding proof-of-concept code and the full chain until no later than 2026-08-28. That is not the same as nothing public existing: Rapid7 records that public code claiming to exploit the flaw exists, while stating it is unclear how closely that code corresponds to the full attack chain reported privately to Rails ([Rapid7, 2026-07-30](https://www.rapid7.com/blog/post/etr-kindarails2shell-cve-2026-66066-critical-arbitrary-file-read-and-possible-remote-code-execution-in-ruby-on-rails)). Ethiack's own framing is the reason this belongs in an out-of-cycle patch conversation rather than a monthly one: it tells operators to assume attackers with AI tooling can reconstruct the chain quickly once the patch diffs are public.

Detection is thin by design here, because a successful read looks like an ordinary upload. The realistic signals are on either side of the processing step: image uploads that fail or crash variant processing at anomalous rates, worker processes reading files well outside the storage tree — application configuration, environment files, key material — and any subsequent use of application secrets from a network location that has never presented them before. The last of these is the one worth instrumenting, since the value of this bug to an attacker is the credential, not the read. Verification is straightforward and worth doing before any of that: check the configured variant processor, the installed gem version against the three fixed points, and the system libvips version against the 8.13 floor.

## Update — 2026-08-02T04:09:57Z

The disclosure timetable this entry's predecessor described has collapsed. Rails shipped the CVE-2026-66066 fixes on 2026-07-29 while deliberately withholding the exploitation mechanics — the security team "held back details about the attack vector to allow applications to be upgraded before malicious attackers could take advantage of the vulnerability" — and intended to publish them no later than 2026-08-28. On 2026-07-31 it abandoned that plan, stating that "several researchers quickly reverse-engineered the attack and have already published proofs-of-concept" ([Ruby on Rails security team, 2026-07-31](https://discuss.rubyonrails.org/t/cve-2026-66066-attack-details-and-tools-to-perform-a-forensic-investigation/91441)). The four-week grace period the prior coverage described as the defender's buffer no longer exists.

Rather than publish prose alone, the team released a repository — `rails/rails-forensics-CVE-2026-66066` — containing four things a responder can use directly: a step-by-step walkthrough of the attack from the incoming request to the file being read, a guide to what evidence the attack leaves in the application database and object store, and, explicitly, what that evidence does and does not prove; plus two artifacts the team calls "agent skill"s rather than scripts, one that "works out whether your application was ever vulnerable, and if it was, over what period of time" and one that "searches your Active Storage data for the crafted files, and works out what was read if it finds any" ([Ruby on Rails security team, 2026-07-31](https://discuss.rubyonrails.org/t/cve-2026-66066-attack-details-and-tools-to-perform-a-forensic-investigation/91441)). The distinction matters operationally: these are skills intended to be driven by an AI coding agent, not standalone command-line tools. The post's author, writing as a member of the Rails security team, states the material was "extracted from work I did at 37signals to perform a forensic analysis on our own apps" — that is, it comes out of one company's real incident response rather than being written for the advisory. Nothing about the vulnerable versions or the preconditions changed: activestorage below 7.2.3.2, 8.0.5.1 and 8.1.3.1 remain affected where the application uses the libvips variant processor and accepts image uploads from untrusted users, and the fix is only effective on libvips 8.13 or newer ([Ruby on Rails GHSA, 2026-07-29](https://github.com/rails/rails/security/advisories/GHSA-xr9x-r78c-5hrm)).

One in-window operational signal accompanies the announcement, and it should be read carefully. A maintainer of the Discourse forum platform replied in the same thread on 2026-08-01 that Discourse has "noticed an increase in this style of attack" and described the defence-in-depth work it shipped that week — moving image processing out of high-privilege processes using Linux Landlock sandboxing, with the stated design goal that an image-resizing process should be able to write to one location rather than hold write access to the whole filesystem ([Discourse maintainer reply on Ruby on Rails Discussions, 2026-08-01](https://discuss.rubyonrails.org/t/cve-2026-66066-attack-details-and-tools-to-perform-a-forensic-investigation/91441)). That observation is about the *class* of attack against image-processing libraries, not about CVE-2026-66066 specifically — the same reply states Discourse currently uses ImageMagick with an allowed-coder list and is only now porting to libvips, so it is not describing exploitation of this Rails flaw ([Discourse maintainer reply on Ruby on Rails Discussions, 2026-08-01](https://discuss.rubyonrails.org/t/cve-2026-66066-attack-details-and-tools-to-perform-a-forensic-investigation/91441)).

**Defender takeaway:** the exposure question has moved from *have we patched* to *were we read before we patched*. Because the flaw yields `secret_key_base`, the master key and everything `credentials.yml.enc` decrypts — storage and database credentials and third-party tokens among them — an application that was internet-reachable, configured for the libvips variant processor and accepting untrusted image uploads during its vulnerable window is a key-rotation candidate, not merely an upgrade candidate — an ImageMagick-configured application is outside the vector entirely and needs neither — and unlike most such judgements, the vendor has now published tooling that answers the question from evidence in the application's own database and object store rather than from guesswork. The prior entry's warning that the patch diffs made reconstruction fast is now settled fact, two days rather than four weeks after the fix.

## Update — 2026-08-10T04:54:00Z

The earlier entry recorded that Rails abandoned its embargo on the Active Storage attack chain four weeks early because researchers had already reconstructed it, and shipped forensic tooling so operators could determine whether they had been exploited. The delta is that the chain is now automated and packaged, and that the code-execution half has been validated more broadly than the original disclosure showed ([Rapid7, 2026-08-03](https://www.rapid7.com/blog/post/ra-kindarails2shell-technical-analysis-cve-2026-66066)).

Rapid7 states it "reproduced the published chain against Rails 6.0.6.1, 6.1.7.10, 7.2.3.1, 8.0.5, and 8.1.3, and confirmed that patched 7.2.3.2, 8.0.5.1, and 8.1.3.1 targets block the crafted representation" — which is a useful independent confirmation that the vendor's fixed versions actually close it. Its Metasploit module "creates crafted direct-upload blobs, confirms the file read against /proc/version, recovers and validates Rails signing material, signs an ImageProcessing variation, and triggers either send/spawn for command payloads or send/eval for native Ruby payloads." The mechanically important finding for anyone who assumed a safer serializer contained this: "This RCE path does not depend on a Marshal object gadget. We validated it against Rails 8.0.5 configured with config.active_support.message_serializer = :json." Applications that moved off Marshal serialization are not insulated.

One correction is worth stating plainly, because it would be easy to record this as an exploitation-status change and it is not one. Rapid7's emergent-threat tracker says "As of July 30, 2026, Rapid7 is not aware of exploitation in the wild", and neither of its posts claims observed scanning, honeypot activity or intrusions ([Rapid7, 2026-07-30](https://www.rapid7.com/blog/post/etr-kindarails2shell-cve-2026-66066-critical-arbitrary-file-read-and-possible-remote-code-execution-in-ruby-on-rails/)). What changed is the cost of exploitation, not evidence of it: the chain went from reconstructable-by-a-researcher to a module anyone can run, against a flaw that needs no authentication and no user interaction.

Detection, telemetry class first. Application and web access logs carry the sequence: a direct-upload blob creation followed within the same session by a variant or representation request for that same blob, where the declared content type claims an image. The file-read primitive surfaces as image processing reaching paths that are not user content — a request whose rendered output derives from a system path rather than an uploaded asset is the anomaly, and Rapid7's own proof-of-concept methodology uses exactly such a read as its confirmation step. **Triage:** ordinary Rails applications create blobs and request variants constantly, so neither event is meaningful alone; the discriminator is a variant request whose processing touches a path outside the application's own storage tree, and the tight upload-then-immediately-transform pairing within one session. **Defender takeaway:** patch state is now the whole control, and the recovery step matters as much as the patch — because the chain's purpose is to recover signing material, an application that sat exposed and unpatched should have its `secret_key_base` and credentials treated as disclosed and rotated, since upgrading does not invalidate what was already read.
