Threat Overview
CVE-2026-66066, also called KindaRails2Shell, is a critical Ruby on Rails Active Storage vulnerability that can allow an unauthenticated attacker to read arbitrary files accessible to the Rails process. The Rails security advisory states that affected applications use libvips for Active Storage image processing and accept image uploads from untrusted users. Exposed files can include process environment data containing secret_key_base, database credentials, cloud storage keys, and other secrets. Compromised signing secrets can enable forged sessions and can lead to remote code execution or lateral movement.
The original Rails advisory was published July 29, 2026. On August 31, SecurityWeek reported that VulnCheck observed threat actors exploiting CVE-2026-66066 in the wild during the prior week. VulnCheck had previously published working exploit material and reported more than 7,100 exposed vulnerable instances in its target intelligence. Rails also published forensic guidance because patching does not revoke secrets that may already have been read.
The file-read mechanism involves unsafe libvips loaders for untrusted content. Public technical analysis describes a crafted MATLAB/HDF5 processing chain that can cause the server to read attacker-selected files. These format details are useful supporting indicators, but they are not universal network signatures because upload paths, filenames, MIME handling, storage backends, and application logging vary by deployment.
References
- Ruby on Rails Security Announcement – July 29, 2026: https://discuss.rubyonrails.org/t/cve-2026-66066-possible-arbitrary-file-read-and-remote-code-execution-in-active-storage-variant-processing/91432
- Rapid7 technical analysis – August 3, 2026: https://www.rapid7.com/blog/post/ra-kindarails2shell-technical-analysis-cve-2026-66066/
- VulnCheck Initial Access Intelligence – August 7, 2026: https://docs.vulncheck.com/initial-access/2026-08-07
- SecurityWeek active exploitation update – August 31, 2026: https://www.securityweek.com/critical-ruby-on-rails-vulnerability-in-attackers-crosshairs/
- Rails forensic guidance repository: https://github.com/rails/rails-forensics-CVE-2026-66066
Impacted Systems
- Vendor/product: Ruby on Rails Active Storage.
- Affected component: Active Storage variant processing with libvips.
- Affected versions:
activestorage < 7.2.3.2;>= 8.0 and < 8.0.5.1;>= 8.1 and < 8.1.3.1. - Fixed versions: 7.2.3.2, 8.0.5.1, and 8.1.3.1 or later in the respective supported branches.
- libvips requirement: fixed Rails behavior requires libvips 8.13 or later because older libvips releases cannot block unsafe loaders.
- Platform: any OS hosting an affected Rails application, commonly Linux, containers, or Windows.
- Required configuration:
config.active_storage.variant_processor = :vipsand untrusted-user image uploads. - Attacker prerequisite: network access to an application workflow that accepts an untrusted image upload. Authentication is not inherently required by the vulnerability.
- Exposure: Internet-facing or otherwise attacker-reachable Rails applications with affected upload/variant processing.
- Unaffected condition: applications not using libvips for Active Storage image processing or that do not accept untrusted image uploads are not affected by the described condition.
Why this matters
The issue moved from public technical disclosure to reported active exploitation. Rails applications often hold high-value signing keys, cloud credentials, database passwords, and third-party tokens in process environment variables. File disclosure can therefore become identity/session compromise, remote code execution, or lateral movement even when the initial exploit does not directly spawn a shell.
Exploitation Status
Reported active exploitation as of August 31, 2026. SecurityWeek reported VulnCheck observations of in-the-wild exploitation. Rails and Rapid7 independently confirm the vulnerable conditions and affected versions. Public research includes working exploit material. Exact attacker infrastructure and payload behavior are not standardized, so IOC-only detection is insufficient.
What this hunt looks for
Suspicious Ruby or Rails child processes, unusual upload behavior, MATLAB/HDF5-like upload indicators, script or executable creation by Rails runtimes, new outbound destinations, process-to-network correlation, and Windows/Linux process-creation fallbacks.
Required logs
DeviceProcessEventsDeviceFileEventsDeviceNetworkEventsCommonSecurityLogwith usable HTTP URL/method telemetrySecurityEventEvent ID 4688 fallbackSyslogfallback on Linux-hosted Rails systems
Hunt 1 – First-Pass: Suspicious Ruby or Rails Child Processes
DeviceProcessEvents
| where TimeGenerated >= ago(30d)
| where InitiatingProcessFileName in~ ("ruby.exe","ruby","puma.exe","puma","unicorn","passenger")
| where FileName in~ ("cmd.exe","powershell.exe","pwsh.exe","bash","sh","curl.exe","curl","wget.exe","wget","python.exe","python","perl","nc","ncat")
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine, SHA256
| sort by TimeGenerated ascHunt 2 – Suspicious Upload Requests to Rails Applications
CommonSecurityLog
| where TimeGenerated >= ago(30d)
| extend HttpMethod=tostring(column_ifexists("RequestMethod",""))
| extend Url=tostring(column_ifexists("RequestURL",""))
| extend UserAgent=tostring(column_ifexists("RequestClientApplication",""))
| where HttpMethod in~ ("POST","PUT","PATCH")
| where Url has_any ("upload","attachment","image","avatar","active_storage")
| summarize Requests=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), URLs=make_set(Url,50), UserAgents=make_set(UserAgent,20), Actions=make_set(DeviceAction,20) by SourceIP, DestinationHostName, bin(TimeGenerated,15m)
| where Requests >= 10
| sort by Requests descHunt 3 – MATLAB or HDF5-Like Content Indicators in Web Telemetry
CommonSecurityLog
| where TimeGenerated >= ago(30d)
| extend Url=tostring(column_ifexists("RequestURL",""))
| extend Msg=tostring(column_ifexists("Message",""))
| where Url has_any (".mat",".h5",".hdf5") or Msg has_any ("MATLAB","application/x-matlab-data","application/x-hdf5","HDF5")
| project TimeGenerated, SourceIP, DestinationIP, DestinationHostName, Url, DeviceAction, Msg
| sort by TimeGenerated ascHunt 4 – Script or Executable Files Written by Ruby or Rails Processes
DeviceFileEvents
| where TimeGenerated >= ago(30d)
| where InitiatingProcessFileName in~ ("ruby.exe","ruby","puma.exe","puma","unicorn","passenger")
| where FileName endswith ".sh" or FileName endswith ".ps1" or FileName endswith ".bat" or FileName endswith ".cmd" or FileName endswith ".py" or FileName endswith ".exe" or FileName endswith ".dll" or FileName endswith ".so"
| project TimeGenerated, DeviceName, ActionType, FileName, FolderPath, SHA256, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by TimeGenerated ascHunt 5 – New Public Destinations From Ruby or Rails Processes
let Baseline = DeviceNetworkEvents
| where TimeGenerated between (ago(30d) .. ago(7d))
| where InitiatingProcessFileName in~ ("ruby.exe","ruby","puma.exe","puma","unicorn","passenger")
| where RemoteIPType == "Public"
| summarize by DeviceId, RemoteIP, RemotePort;
DeviceNetworkEvents
| where TimeGenerated >= ago(7d)
| where InitiatingProcessFileName in~ ("ruby.exe","ruby","puma.exe","puma","unicorn","passenger")
| where RemoteIPType == "Public"
| join kind=leftanti Baseline on DeviceId, RemoteIP, RemotePort
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, RemoteIP, RemoteUrl, RemotePort, ActionType
| sort by TimeGenerated descHunt 6 – Ruby Child Process Followed by Public Network Activity
let SuspiciousChildren = DeviceProcessEvents
| where TimeGenerated >= ago(30d)
| where InitiatingProcessFileName in~ ("ruby.exe","ruby","puma.exe","puma","unicorn","passenger")
| where FileName in~ ("cmd.exe","powershell.exe","pwsh.exe","bash","sh","curl.exe","curl","wget.exe","wget","python.exe","python")
| project DeviceId, DeviceName, ProcessTime=TimeGenerated, ChildProcess=FileName, ChildCommandLine=ProcessCommandLine;
DeviceNetworkEvents
| where TimeGenerated >= ago(30d)
| join kind=inner SuspiciousChildren on DeviceId
| where TimeGenerated between (ProcessTime .. ProcessTime + 10m)
| project ProcessTime, TimeGenerated, DeviceName, ChildProcess, ChildCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine, RemoteIP, RemoteUrl, RemotePort, ActionType
| sort by ProcessTime ascHunt 7 – Windows SecurityEvent Fallback for Ruby-to-Shell Execution
SecurityEvent
| where TimeGenerated >= ago(30d)
| where EventID == 4688
| where ParentProcessName has_any ("ruby.exe","puma","passenger")
| where NewProcessName has_any ("cmd.exe","powershell.exe","pwsh.exe","wscript.exe","cscript.exe","curl.exe","certutil.exe")
| project TimeGenerated, Computer, Account, ParentProcessName, NewProcessName, CommandLine
| sort by TimeGenerated ascHunt 8 – Linux Syslog Fallback for Rails Post-Exploitation
Syslog
| where TimeGenerated >= ago(30d)
| where SyslogMessage has_any ("ruby","puma","passenger","rails")
| where SyslogMessage has_any ("sudo","session opened for user root","curl ","wget ","bash ","sh ","chmod +x","systemctl","crontab")
| project TimeGenerated, Computer, HostIP, ProcessName, SeverityLevel, SyslogMessage
| sort by TimeGenerated ascDetection Notes
- Highest-signal post-exploitation behavior is a Ruby, Puma, Passenger, or related Rails runtime spawning shells, download utilities, or script interpreters.
- Web upload hunts are supporting telemetry and must be adapted to the application’s actual upload endpoints. A generic URL containing
uploadoractive_storageis not proof of exploitation. - MATLAB/HDF5 indicators come from the publicly described attack mechanism but may not appear in URL or proxy telemetry if content is multipart, renamed, encoded, or stored out of band.
- Microsoft Defender does not provide a general file-read event for arbitrary server files, so the actual secret-read primitive may leave no endpoint file-read event in Sentinel.
- Broad Ruby process hunting can be noisy on development, CI/CD, and automation hosts. Scope to confirmed Rails application servers when asset context is available.
- Missing WAF/reverse-proxy telemetry or endpoint coverage on the Rails server substantially reduces visibility.