A crafted image can reach unsafe libvips operations through Active Storage, exposing files and process credentials that a Rails-only update cannot recover.2026-08-025 min2026appseccloud
5 min read
Read format

Rails Image Processing Could Expose Every Secret in the App Process

A crafted image can reach unsafe libvips operations through Active Storage, exposing files and process credentials that a Rails-only update cannot recover.

By Justin Howe
A server-side photo processor pulls credential envelopes and key cards from a sealed compartment while handling an uploaded image.

Ruby on Rails disclosed a critical Active Storage flaw that can let an unauthenticated attacker read arbitrary files from a Rails server through a crafted image upload. The vulnerable path can expose the application process environment, where deployments commonly keep secret_key_base, storage credentials, database passwords, and tokens for other services.

CVE-2026-66066 affects applications that use libvips for Active Storage image processing and accept images from untrusted users. Rails rated it 9.5 under CVSS v4. The maintainers say exposed process credentials can support remote code execution or lateral movement, but neither the advisory nor the researchers’ public reports establish exploitation in the wild.

Active Storage passed untrusted content to operations built for more than images

Active Storage uses libvips to build image variants such as avatars and thumbnails. libvips, in turn, reads and writes formats through loaders, savers, and other operations supplied by its own code and linked third-party libraries. Some are marked unfuzzed because they are not considered safe for untrusted content. Several handle formats unrelated to ordinary web images.

Before the fix, Active Storage did not disable those unfuzzed operations. Rails says an attacker who can upload a crafted file can cause libvips to invoke one of them and disclose a file that the application process can read. The advisory also says variant generation is not a separate exposure condition, so an inventory limited to routes that explicitly request thumbnails can miss an affected upload path.

Ethiack’s coordinated disclosure narrows the deployment conditions. The application must use the vips processor, accept untrusted image uploads, and run a libvips build linked against certain third-party libraries. Common Rails 7.x and 8.x configurations can meet those conditions. Rails 6.x requires a non-default Active Storage setup. Applications using ImageMagick rather than libvips are not affected by this vector.

Trust-boundary diagram showing how an untrusted image reaches an unfuzzed libvips operation, process-readable secrets, and possible downstream access.

Figure details

An untrusted user sends a crafted image to a Rails application that accepts uploads. Active Storage passes the file into its vips variant processor. Before the fix, that processor could invoke a libvips operation marked unfuzzed. The operation could read files and environment values available to the Rails process, including secret_key_base, the Rails master key, storage credentials, database credentials, and third-party tokens. Those secrets can affect Rails sessions and signed data or provide identities for storage, database, cloud, and other connected systems. The fixed Active Storage releases disable unfuzzed operations and require libvips 8.13 or later. Secret replacement is still required because the update cannot invalidate material already disclosed.

The attack chain’s implementation remains partly undisclosed. Rails plans to release technical details no later than August 28, 2026. That withholding limits signature development and means responders should not claim that a clean WAF or payload scan proves a deployment was untouched.

The patch closes the operation, not the credential exposure

Fixed Active Storage versions are 7.2.3.2, 8.0.5.1, and 8.1.3.1. The update disables the unsafe libvips operations before processing untrusted content. It also requires libvips 8.13 or later because older builds cannot block those operations. An affected application can therefore fail to boot after the Rails update until the underlying library is upgraded.

For libvips 8.13 or later, VIPS_BLOCK_UNTRUSTED is a temporary control when an immediate Rails upgrade is impossible. Applications using ruby-vips 2.2.1 or later can call Vips.block_untrusted(true) during initialization. Ethiack says a WAF may reduce exposure in some architectures but is not a fix.

GMO Flatt Security, which independently found the flaw, describes remote code execution as possible in common affected configurations rather than inevitable in every Rails deployment. The distinction matters. File disclosure is the directly documented capability. Remote execution depends on what the process can read and how those secrets authorize Rails or connected systems.

The update cannot recover a credential that already left the server. Rails tells affected operators to replace secret_key_base; the Rails master key and every value it decrypts; Active Storage keys for S3, Google Cloud Storage, or Azure; database credentials; and tokens for third-party services. Rotation is only an intermediate step when an old value remains valid as a fallback.

Changing secret_key_base expires active sessions and changes encrypted or signed cookies, signed global IDs, and Active Storage URLs. That disruption is evidence that the old signing material is no longer accepted, not an incidental side effect to avoid.

Defenders should prove both the code path and every exposed identity changed

First, inventory the deployed activestorage version, config.active_storage.variant_processor, the system libvips version, and every route or background job that accepts or processes an image from an untrusted user. Confirm production runs 7.2.3.2, 8.0.5.1, 8.1.3.1, or later and libvips 8.13 or later. Restart each web and worker process and capture successful boot evidence. If a temporary block is used, verify VIPS_BLOCK_UNTRUSTED or Vips.block_untrusted(true) is active in every process class, not only the web tier.

Second, build a credential inventory from the actual process environment, config/master.key, RAILS_MASTER_KEY, config/credentials.yml.enc, Active Storage service configuration, database configuration, and service clients. Replace every reachable secret at its issuing system, remove the old value rather than retaining it as fallback, and verify the old credential fails. Expire existing Rails sessions and signed artifacts tied to the previous secret_key_base.

Review upload, request, worker, storage, cloud, database, and identity-provider records from the earliest untrusted-image exposure through credential replacement. Look for unusual image uploads followed by variant-processing errors, reads or requests outside normal image paths, new storage or database sessions, and third-party access using the application’s identities. Those checks can find consequences, but the withheld exploit details and incomplete file-read telemetry remain a material blind spot.

Close the exposure only when the affected upload paths are patched or removed, every Rails and worker process uses a safe libvips configuration, all process-readable credentials have been replaced without valid fallbacks, old sessions and signing material are rejected, and downstream access has been reconciled through the replacement time. Missing upload history, process telemetry, or service-side authentication records leaves the incident unresolved.

Primary sources

Continue reading

Article figurePinch or double-tap to zoom, then drag to pan.