Neutron, our AI engine, scored 97.1% on UC Berkeley's CyberGym benchmark. Learn more

Deep Dive

Deep Dive

Rails Active Storage RCE, Fixed in 8.1.4.1 (GHSA-f3w6-w445-fwh9)

Rails Active Storage before 8.0.5.2 and 8.1.4.1 lets crafted uploads make ImageMagick or FFmpeg write or read server files, possibly leading to RCE; update now.

TL;DR

  • A crafted upload to a Rails application that processes attachments with ImageMagick may let an unauthenticated attacker write arbitrary files on the server. The Rails team disclosed the flaw on November 4, 2026.
  • Active Storage versions before 8.0.5.2 and the 8.1 series before 8.1.4.1 are affected. A second flaw in the same release lets an uploaded filename choose which FFmpeg or ImageMagick decoder runs on the file.
  • The Rails team rates the file-write flaw Critical (CVSS v3.0 9.8) and the decoder flaw High (CVSS v3.1 8.8). No CVE is assigned, and neither flaw is in CISA's Known Exploited Vulnerabilities (KEV) catalog as of November 4, 2026.
  • Update activestorage to 8.0.5.2 or 8.1.4.1 now, and read the migration notes: the fix ships an ImageMagick policy that requires mini_magick 5.1 or later. See "How do I fix it?".

Am I affected?

For the Critical file-write flaw, GHSA-f3w6-w445-fwh9, all of these conditions must hold:

  • Your application processes Active Storage attachments with ImageMagick. That is config.active_storage.variant_processor = :mini_magick, the default for applications on load_defaults 6.1 or earlier.
  • Your host runs ImageMagick under a security policy that does not already deny the coders involved. Check your policy.xml for MSL, MVG and the Ghostscript-backed coders. Debian 12's packaged policy denies the Ghostscript and URL coders, but it has no MSL rule and its only MVG rule is commented out, so it does not block the reported chain.
  • Your application allows file uploads from untrusted users.

For the High decoder flaw, GHSA-v924-7rp8-4mxh, all of these conditions must hold:

  • Your application accepts uploads from untrusted users.
  • It analyzes video or audio attachments, which Active Storage does on attach by default, generates video previews, or processes images with ImageMagick.

The decoder flaw's AviSynth path needs an FFmpeg built with --enable-avisynth and the AviSynthPlus runtime. Upstream FFmpeg and the packages shipped by mainstream Linux distributions and Homebrew do not enable it. The GPL builds distributed for Windows and Linux from ffmpeg.org do, and other extension-selected decoders may be reachable without AviSynth.

Branch Affected versions Fixed version
8.1.x 8.1.0 to 8.1.4 8.1.4.1, released 2026-11-04
8.0.x 8.0.0 to 8.0.5.1 8.0.5.2, released 2026-11-04
7.2 and every earlier series No fix will ship; the series is unsupported Upgrade to at least 8.0.5.2

Rails security releases ship for the 8.0 and 8.1 series only, and the 8.0 series leaves security support on November 7, 2026 per the maintenance policy. Applications on 7.2 or earlier should treat this release as the deadline to move to a supported series. The activestorage gem has been downloaded 561,823,760 times on RubyGems as of November 4, 2026; the rails gem, 811,345,791.

Check what you run:

# Version in the application's Gemfile.lock
grep -m1 'activestorage (' Gemfile.lock

# Version of the installed gem
bundle info activestorage | head -1

# Which variant processor is configured (no output means the framework default)
grep -R 'variant_processor' config/

# Does your FFmpeg admit the AviSynth demuxer? (prints the flag when enabled)
ffmpeg -version | grep -i avisynth

How do I fix it?

  1. Move the application to a fixed release. Pin the rails gem to 8.1.4.1, or 8.0.5.2 on the 8.0 series:
# Gemfile
gem "rails", "~> 8.1.4.1"

# then
bundle update rails
  1. Read the migration notes before deploying. The fixed releases apply an ImageMagick security policy to every ImageMagick process MiniMagick spawns, which requires mini_magick 5.1 or later. An application on an older mini_magick raises an exception during boot.
  2. Recreate application containers if you deploy in containers. Pulling a new image without recreating the running container leaves the old code in place.
  3. If your application renders PostScript or PDF through ImageMagick, re-allow the gs delegate and the coders it uses in the host's policy.xml, because the shipped policy denies them. A host policy that allows a coder overrides the shipped deny.
  4. Carry the shipped policy's rules in ImageMagick's system policy if the shipped policy cannot reach your application. That is the case when the application:
    • replaces MiniMagick.cli_env after boot, clears the environment with MiniMagick.cli_prefix, or installs its own MiniMagick::Shell;
    • uses GraphicsMagick, which does not read ImageMagick policies.

For applications that cannot upgrade yet, the advisory's workaround is to copy the rules of the shipped policy into ImageMagick's system policy. The shipped file is activestorage/lib/active_storage/image_magick/policy.xml, and a common system path is /etc/ImageMagick-7/policy.xml. At a minimum, deny the MSL coder, the Ghostscript coders, and the gs delegate:

<policy domain="coder" rights="none" pattern="MSL"/>
<policy domain="delegate" rights="none" pattern="gs"/>
<policy domain="coder" rights="none" pattern="{PS,PS2,PS3,EPS,EPS2,EPS3,EPI,EPSF,EPSI,EPT,EPT2,EPT3,PDF,AI,EPDF,PDFA,POCKETMOD,XPS,PCL}"/>

For the decoder flaw, applications that cannot upgrade can stop Active Storage from running FFmpeg on uploaded files, adapted from the advisory. This closes the FFmpeg path, but not the extension-selected decoders of ImageMagick:

# config/environments/production.rb
config.active_storage.previewers =
  ActiveStorage.previewers - [ActiveStorage::Previewer::VideoPreviewer]
config.active_storage.analyzers =
  ActiveStorage.analyzers - [ActiveStorage::Analyzer::VideoAnalyzer, ActiveStorage::Analyzer::AudioAnalyzer]

What is the root cause?

Two properties of external tools met two Active Storage defaults.

For the Critical flaw, ImageMagick selects a coder from the content of the file it is given. Some coders then act on files named inside the image rather than on the image itself. The MSL coder is ImageMagick's XML scripting interface: it reads and writes files named inside the image. Others read or delete a file other than the image, or hand the file to the Ghostscript delegate.

Active Storage constrained none of ImageMagick's coders before this release. The ImageMagick analyzer runs when a file is attached, so attaching the upload is sufficient to reach a coder. No variant, preview or analyze call is required.

The fix commit for 8.1, 468aa9a93fc98f5476b6821770f4ccfcb7f7d328 ("Ship an ImageMagick security policy for every MiniMagick process", November 3, 2026), adds the policy and wires it in through the engine:

# activestorage/lib/active_storage/engine.rb at 8.1.4.1
if ActiveStorage::MINIMAGICK_AVAILABLE && !ActiveStorage::MINIMAGICK_UNSECURABLE
  ActiveStorage::ImageMagick.apply_policy
end

For the High flaw, ActiveStorage::Blob#open writes a blob to a tempfile whose name carries the extension of the uploaded filename, then hands that path to ffprobe, ffmpeg and ImageMagick. The vulnerable line, at 8.1.4:

# activestorage/app/models/active_storage/blob.rb, line 324 at v8.1.4
def open(tmpdir: nil, &block)
  service.open(
    key,
    checksum: checksum,
    verify: !composed,
    name: [ "ActiveStorage-#{id}-", filename.extension_with_delimiter ],
    tmpdir: tmpdir,
    &block
  )
end

filename.extension_with_delimiter is the uploader's choice. FFmpeg picks its AviSynth demuxer on a .avs extension alone, and ImageMagick selects coders and delegates from the extension the same way.

How is it exploited?

For the Critical flaw:

  1. The attacker uploads a crafted file to an affected application. The file only has to be attached; the analyzer runs on attach, and no variant, preview or analyze call is required.
  2. ImageMagick picks a coder from the file's content. In the reported chain, an uploaded SVG reached the MSL scripting coder, which reads and writes the files its script names.
  3. The coder writes attacker-chosen files on the server. When attachments are stored with the Disk service, the same class of coders can read arbitrary files readable by the application process.
  4. Those files typically include secret_key_base and credentials for external systems. The advisory states this may allow escalation to remote code execution or lateral movement, and that one specific attack chain was reported but others may exist.

For the High flaw, the fix's own tests document the attack names:

  1. The attacker uploads a file named attack.avs and declares its content type video/mp4. The blob is analyzed on attach, so Active Storage hands the tempfile to ffprobe and ffmpeg.
  2. Because the tempfile's name ends in .avs, an FFmpeg built with AviSynth support evaluates the file as an AviSynth script.
  3. The script imports files readable by the application process and discloses them through the preview image. It can also load a native library the attacker uploaded, possibly leading to remote code execution in the FFmpeg process.
  4. Other decoders that FFmpeg or ImageMagick select from the extension may be reachable without AviSynth. The tests also cover evil.mp4, an upload declared image/png whose content is a playlist naming a local file. Its .mp4 extension could make ImageMagick delegate it to FFmpeg.

How does the attack flow?

An unauthenticated upload reaches an external tool that takes its instructions from the upload, and the tool then acts on files the attacker names.

flowchart LR A["Untrusted upload"] --> B["Attaching the file
runs the analyzer"] B --> C["ImageMagick picks a coder
from the file content"] C --> D["No policy constrains
the coders"] D --> E["MSL coder acts on files
named inside the image"] E --> F["Arbitrary file write on
the server"] F --> G["Disk service: secret files read,
possible escalation to code execution"]

What can an attacker do?

The Critical flaw may give an unauthenticated uploader arbitrary file writes on the server. The Rails team scores it CVSS v3.0 9.8, CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. It needs three conditions together: an ImageMagick variant processor, a host policy that does not already deny the coders involved, and uploads from untrusted users.

The MSL coder and similar file-writing coders also read files when attachments use the Disk service, which typically exposes secret_key_base, the master key, and credentials for external systems. The Rails team states this may allow escalation to remote code execution or lateral movement to those systems.

The High flaw may disclose files readable by the application process through a generated preview image. The Rails team scores it CVSS v3.1 8.8, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, which assumes an attacker with low privileges on the application.

For the High flaw, both the file disclosure and the code execution require an FFmpeg built with AviSynth support. Other extension-selected decoders may be reachable without AviSynth, but the advisory names no specific impact for them.

Why does the fix work?

The Critical fix constrains every ImageMagick process MiniMagick spawns, not only the analyzer's. The shipped policy denies:

  • the MSL coder, and the coders that read or delete files other than the image;
  • remote and local references, and screen display;
  • every Ghostscript-backed coder, together with the gs delegate;
  • @filename indirection.

Because ImageMagick applies every policy.xml on its search path, the shipped policy adds to the host's policy rather than replacing it.

The High fix stops the uploaded filename from choosing the decoder. The tempfile keeps the extension only when Marcel maps that extension to the blob's recorded content type, and carries no extension otherwise. The fix commit, 72136ff39153bc8d63ecbc899993848eb3d6573e ("Active Storage: tempfile extension must match the blob's content type"), replaces the raw extension with a validated choice:

--- a/activestorage/app/models/active_storage/blob.rb
+++ b/activestorage/app/models/active_storage/blob.rb
@@ -321,7 +322,7 @@ def open(tmpdir: nil, &block)
       key,
       checksum: checksum,
       verify: !composed,
-      name: [ "ActiveStorage-#{id}-", filename.extension_with_delimiter ],
+      name: [ "ActiveStorage-#{id}-", tempfile_extension ],
       tmpdir: tmpdir,
       &block
     )
@@ -360,6 +361,25 @@ def service
   end

   private
+    # The extension is there for tools that cannot tell the type from the bytes (316d87e4: ImageMagick
+    # needs it for an SVG with no XML declaration), but some tools choose a decoder on it alone: FFmpeg
+    # runs a `.avs` file as an AviSynth script. So the uploaded extension is kept only when it denotes
+    # the blob's media type.
+    def tempfile_extension
+      extension = filename.extension_with_delimiter
+      return "" if extension.blank?
+
+      type_for_extension = Marcel::MimeType.for(name: filename.to_s)
+      return "" if type_for_extension == Marcel::MimeType::BINARY || type_for_extension != media_type
+
+      extension
+    end
+
+    # Marcel answers in canonical lowercase, so drop parameters and case before comparing.
+    def media_type
+      content_type.to_s.split(";").first.to_s.strip.downcase
+    end
+
     def compute_checksum_in_chunks(io)

Files whose uploaded extension disagrees with their content type are still processed, and the external tool then detects their format from the content. A form upload whose Rack tempfile fails the same check is copied to a correctly named tempfile before processing.

The Critical fix narrows the attack surface without proving that no other chain exists. The advisory states that one attack chain was reported and that the Rails team does not assume it is the only one. Some applications never receive the shipped policy; see "How do I fix it?".

How do I check if I was compromised?

Rails publishes no indicators for either flaw. An attempt that failed may leave no trace.

For the Critical flaw, review the server for files the application user did not create, in particular in web-served paths. If your application met the affected conditions and stored attachments with the Disk service before you upgraded, treat every secret readable by the application process as exposed. The advisory names secret_key_base, the master key, everything config/credentials.yml.enc holds, storage and database credentials, and third-party tokens.

For the High flaw, an application that ran an FFmpeg with AviSynth support should treat every secret readable by the application process as exposed, for the same set. Changing secret_key_base expires active sessions and invalidates signed and encrypted cookies, signed global IDs and Active Storage URLs.

Timeline

The tempfile fix was authored 53 days before the coordinated releases shipped.

The Rails tempfile fix was authored on September 12 and the coordinated release shipped on November 4.
Figure 1: From the first fix commit to the coordinated release. Source: Rails fix commits and GitHub releases, checked November 4, 2026

  • 2026-09-12: The tempfile-extension fix was authored in the 8.1 branch (commit 72136ff3).
  • 2026-11-03: The ImageMagick security policy fix was committed (commit 468aa9a9, 20:10 UTC).
  • 2026-11-04: Rails 8.0.5.2 (02:31 UTC) and 8.1.4.1 (02:46 UTC) were released on GitHub.
  • 2026-11-04: The coordinated announcement of the 21 fixed issues was posted to oss-security (02:58 UTC).
  • 2026-11-04: The two advisories were published (GHSA-v924-7rp8-4mxh at 03:02 UTC, GHSA-f3w6-w445-fwh9 at 03:09 UTC).

FAQ

Does the fix change how my application boots?

An application whose variant processor is :mini_magick needs mini_magick 5.1 or later, because applying the policy requires it. With an older mini_magick the application raises an exception during boot. Applications using libvips, the default from load_defaults 7.0, are unaffected by this requirement.

I use libvips. Am I affected?

The Critical file-write flaw needs the ImageMagick variant processor, so a libvips application is not affected by it. The High decoder flaw applies regardless of processor: video and audio attachments are analyzed with ffprobe on attach by default, and the tempfile naming fix covers that path.

My application renders PDF or PostScript through ImageMagick. What now?

The shipped policy denies every Ghostscript-backed coder and the gs delegate. Your application must re-allow the delegate and the coders it uses in the host's policy.xml, or the rendering stops working after the update.

What are the other 19 security issues in this release?

The same release fixes three further High issues: a Strong Parameters bypass in Parameters#each_key, IP spoofing in Action Dispatch RemoteIp (8.1 only), and a denial of service in safe_constantize. The other 16 are rated Medium or Low, among them cross-site scripting (XSS), denial-of-service and session-handling fixes. The oss-security announcement links every advisory.

Why is no CVE assigned?

The Rails team published both flaws as repository security advisories, and neither carries a CVE id as of November 4, 2026. Neither is in the GitHub Advisory Database on that date either, so dependency scanners that rely on CVE records or on that database may not flag them. Check your Gemfile.lock against the fixed versions directly.

My Rails series is 7.2 or earlier. What do I do?

No fix will ship for your series, because it is unsupported. Upgrade to at least 8.0.5.2, and plan the move off 8.0: its security support ends on November 7, 2026.

Find exposed Rails applications before an attacker does

Rails applications that accept uploads from untrusted users are the ones to patch first. Ostorlab's Web Agentic Deep Scan scans your web applications and APIs for vulnerabilities, which helps you find the upload endpoints exposed to untrusted users.

References

  • GHSA-f3w6-w445-fwh9, Rails security advisory, "Possible arbitrary file write and read in Active Storage image analysis": https://github.com/rails/rails/security/advisories/GHSA-f3w6-w445-fwh9 (checked November 4, 2026)
  • GHSA-v924-7rp8-4mxh, Rails security advisory, "Possible arbitrary file read and remote code execution in Active Storage video previews, analysis and image processing": https://github.com/rails/rails/security/advisories/GHSA-v924-7rp8-4mxh (checked November 4, 2026)
  • Rails security releases announcement, 21 issues fixed in 8.0.5.2 and 8.1.4.1: https://www.openwall.com/lists/oss-security/2026/11/04/2 (checked November 4, 2026)
  • Fix commit 468aa9a93fc98f5476b6821770f4ccfcb7f7d328, "Ship an ImageMagick security policy for every MiniMagick process" (8.1): https://github.com/rails/rails/commit/468aa9a93fc98f5476b6821770f4ccfcb7f7d328 (checked November 4, 2026)
  • Fix commit 72136ff39153bc8d63ecbc899993848eb3d6573e, "Active Storage: tempfile extension must match the blob's content type" (8.1): https://github.com/rails/rails/commit/72136ff39153bc8d63ecbc899993848eb3d6573e (checked November 4, 2026)
  • Fix commit ea8c40121ce53a3d0255cd4eb6d13bfe3bc01776, "Ship an ImageMagick security policy for every MiniMagick process" (8.0): https://github.com/rails/rails/commit/ea8c40121ce53a3d0255cd4eb6d13bfe3bc01776 (checked November 4, 2026)
  • Fix commit 8106938fb0a595f11006dd1497cd409e27d7d636, "Active Storage: tempfile extension must match the blob's content type" (8.0): https://github.com/rails/rails/commit/8106938fb0a595f11006dd1497cd409e27d7d636 (checked November 4, 2026)
  • Active Storage CHANGELOG at v8.1.4.1: https://github.com/rails/rails/blob/v8.1.4.1/activestorage/CHANGELOG.md (checked November 4, 2026)
  • Rails 8.0.5.2 release: https://github.com/rails/rails/releases/tag/v8.0.5.2 (checked November 4, 2026)
  • Rails 8.1.4.1 release: https://github.com/rails/rails/releases/tag/v8.1.4.1 (checked November 4, 2026)
  • Active Storage gem downloads: https://rubygems.org/gems/activestorage (checked November 4, 2026)
  • Rails maintenance policy: https://rubyonrails.org/maintenance (checked November 4, 2026)
  • ImageMagick security policy documentation: https://imagemagick.org/security-policy/ (checked November 4, 2026)
  • Debian 12 packaged ImageMagick policy.xml: https://sources.debian.org/src/imagemagick/8:6.9.11.60+dfsg-1.6+deb12u11/config/policy.xml/ (checked November 4, 2026)