Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
KindaRails2Shell — Single-file PoC for Rails CVE-2026-66066: arbitrary file read, secret recovery, threaded scanning, and conditional RCE via signed image variations. | Kitploit
Tools/GitHubGitHub/0xsha/kindarails2shell
Vulnerability ScannersExploitationWeb Application ExploitationWeb SecurityPenetration TestingPayload DevelopmentLabs & Practice
GitHub0xsha/kindarails2shell

KindaRails2Shell

Single-file PoC for Rails CVE-2026-66066: arbitrary file read, secret recovery, threaded scanning, and conditional RCE via signed image variations.

View Repository
2220 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

KindaRails2Shell: CVE-2026-66066

A zero-dependency, single-file proof of concept and loopback-only Docker lab for the Rails Active Storage/libvips arbitrary-file-read vulnerability. It also demonstrates the advisory's conditional escalation from a recovered secret_key_base to a forged image variation and command execution.

  • Affected: Rails 7.2.0–7.2.3.1, 8.0.0–8.0.5, and 8.1.0–8.1.3
  • Fixed: Rails 7.2.3.2, 8.0.5.1, and 8.1.3.1
  • Runtime: Python 3.11+, standard library only
  • Scope: authorized testing and local research

Primary references: Rails advisory, Rails forensic analysis, the Ethiack technical write-up, and the 8.1.3.1 release.

Demo

https://github.com/user-attachments/assets/fdcb5651-c1d1-4bc4-b322-8f1205b09635

Why this PoC is useful

kr2s.py contains the complete client in one file:

  • an embedded, patchable HDF5/MAT payload with no h5py or numpy;
  • direct-upload delivery and automatic CSRF handling;
  • variation-key harvesting from an existing Active Storage thumbnail;
  • a strict, standard-library PNG decoder for byte-exact recovery;
  • arbitrary offsets and reads up to 16 MiB per request;
  • secret discovery and a pure-Python Rails variation signer;
  • command-output read-back with a random marker and best-effort cleanup;
  • threaded passive or explicitly active scanning with JSON reports;
  • proxy, custom path, TLS, timeout, and user-agent controls.

The tool does not install packages, start a callback listener, require curl on the target, or depend on make. The RCE stage uses the built-in Active Storage representation route and does not require a Marshal gadget.

Quick start

Start the vulnerable lab:

root@kitploit:~
cd lab
RAILS_VERSION=8.1.3 docker compose up --build

The Compose port is bound to 127.0.0.1 and the container runs as an unprivileged user with all Linux capabilities dropped.

In another terminal:

root@kitploit:~
# Intrusive: uploads a blob, then confirms /etc/hostname is readable.
python3 kr2s.py check http://127.0.0.1:3000

# Recover a fixed-size prefix. Binary output goes to stdout unless -o is used.
python3 kr2s.py read http://127.0.0.1:3000 /etc/passwd --size 4096
python3 kr2s.py read http://127.0.0.1:3000 /etc/passwd -o passwd.bin

# Recover selected environment secrets. Values are redacted by default.
python3 kr2s.py secrets http://127.0.0.1:3000

# Display complete matched environment values for authorized analysis.
python3 kr2s.py secrets http://127.0.0.1:3000 --show-full

# Passive preflight of one target or a file containing one target per line.
python3 kr2s.py scan http://127.0.0.1:3000
python3 kr2s.py scan targets.txt --threads 10 --json scan.json

# Intrusively confirm file read on every target in the list.
python3 kr2s.py scan targets.txt --active

# Probe selected libvips loaders.
python3 kr2s.py probe http://127.0.0.1:3000

# Conditional escalation. This executes the supplied command.
python3 kr2s.py rce http://127.0.0.1:3000 "id; uname -a"

Run python3 kr2s.py COMMAND --help for all overrides. Common real-application controls include --harvest-url, --show-path, --proxy, --insecure, and --skb.

secrets --show-full prints complete matched environment-variable values. Without it, the tool prints only the first 12 characters and an ellipsis. Files requested with --also-read, including the default Rails credential paths, are printed up to 600 characters when readable.

Passive scan only reports whether the page exposes a harvestable Active Storage representation; it cannot identify the installed Rails patch level. scan --active uploads a malicious blob and attempts the canary read. A failed active result is labelled BLOCKED_OR_INCONCLUSIVE, not SAFE, because WAFs, authentication, unsupported variations, and the Rails fix can look identical from outside the application.

Stop the lab with:

root@kitploit:~
cd lab
docker compose down

What the exploit does

  1. The client reserves an Active Storage direct upload declared as image/png.
  2. It uploads a hybrid MATLAB/HDF5 file. The HDF5 dataset uses external storage whose filename and offset point to a file in the Rails process.
  3. A server-signed variation key is harvested from an existing thumbnail and reused with the malicious blob's signed ID.
  4. Vulnerable Rails passes the data to libvips matload; target-file bytes become image pixels and return in a generated PNG.
  5. The client validates and decodes the PNG, then reverses matio's column-major layout to recover the original bytes.

The hybrid file satisfies two parsers at once: its text starts with MATLAB 5.0, while the version word at offset 124 selects the HDF5-backed MATLAB 7.3 path. Rails' fix blocks libvips operations marked untrusted before an attacker-controlled file can reach matload.

Conditional RCE

rce first reads SECRET_KEY_BASE from /proc/self/environ, unless --skb is provided. It derives the Active Storage verifier key and signs a JSON variation containing an instance_eval operation. On the affected vips path, the operation reaches Vips::Image.public_send. The PoC sends it through the built-in representation route, runs the supplied command through /bin/sh, and captures both output streams.

This second stage is conditional on recovering the signing secret and reaching the vulnerable vips transformation behavior described in Ethiack's analysis of CVE-2025-24293. The CVE-2026-66066 patch closes the file-read entry point; it is not a general fix for previously leaked signing secrets. Rotate secrets after suspected exposure, as the Rails advisory recommends.

Command output is written to a random /tmp/.kr2s_* file, recovered through the same file-read primitive, and then removed with a second signed payload.

Read behavior and limits

Reads return the requested fixed-size region. If the source is shorter, its prefix is followed by zero bytes. Use --offset for subsequent regions.

The default lab variation only converts to PNG, so recovery is byte-exact. Real applications may resize variants. The harvested-key mode uses a one-pixel column to avoid horizontal resampling, but a variation with a lower height can still change the geometry. In that case the client fails explicitly; reduce --size or harvest a non-resizing representation.

Every command is intrusive: it creates persistent Active Storage blobs and may create processed variants. rce additionally executes the supplied command.

Version matrix

The matrix script builds each release, runs real read and RCE checks on vulnerable versions, asserts that reads are blocked on fixed versions, and returns nonzero on any mismatch:

root@kitploit:~
./lab/matrix.sh
./lab/matrix.sh 8.1.3
./lab/matrix.sh 8.1.3.1:PATCHED

Validated on 2026-07-31 with Ruby 3.4.10, image_processing 1.14.0, ruby-vips 2.3.0, and libvips 8.16.1:

Patched rows deliberately do not fire an RCE payload with a pre-supplied signing secret; the matrix tests the CVE's file-read boundary.

Research utilities

research/craft.py regenerates candidate payloads for loader research and requires h5py plus numpy. It is not imported by the release PoC. lab/probe/probe.sh inspects those candidates with ruby-vips inside a lab image:

root@kitploit:~
uv run --script research/craft.py all -o /tmp/kr2s-payloads
docker run --rm \
  -v "$PWD/lab/probe:/probe:ro" \
  -v /tmp/kr2s-payloads:/payloads:ro \
  --entrypoint /probe/probe.sh kr2s-rails:8.1.3

Run the dependency-free unit tests with:

root@kitploit:~
python3 -m unittest discover -s tests -v

Public-work provenance

The MAT/HDF5 payload and dependency-free client were developed through local testing. After public PoCs appeared, this release incorporated variation-key harvesting and built-in Active Storage routes documented by Zer0SumGam3's PoC. The Python implementation here is original and standard-library-only.

An earlier revision demonstrated that RCE was also possible with a signed Marshal payload using Puma::MiniSSL::Context and an ActiveSupport proxy, based on Behrad Taher's public gadget research. That route avoided target-side helper binaries, but required a Marshal-capable signed-ID sink plus loaded Puma and ActiveSupport gadget classes. It was replaced after the Ethiack Research Team published their KindaRails2Shell technical write-up, which documents the simpler signed JSON variation technique. It uses a stock route and removes those preconditions.

Discovery credit belongs to André Baptista (0xacb), Bruno Mendes (s3np41k1r1t0), Rafael Castilho and the Ethiack Research Team, and RyotaK (GMO Flatt Security). Abdelmounaim Moulahcene (bl0rph) independently published the underlying primitive shortly before the coordinated disclosure. See the Rails forensic repository for the maintainers' full timeline and credits.

Responsible use and license

Use only on systems you own or are explicitly authorized to test. The authors accept no liability for misuse. See SECURITY.md for reporting issues in this research artifact.

Released under the MIT License.

Download Tool
RailsFile readRCE checkResult
7.2.3.1READ-OKRCE-OKpass
7.2.3.2blockednot runpass
8.0.5READ-OKRCE-OKpass
8.0.5.1blockednot runpass
8.1.3READ-OKRCE-OKpass
8.1.3.1blockednot runpass