Introduction
A single crafted upload to a Rails application that processes images with ImageMagick could let an unauthenticated attacker write arbitrary files on the server and, where attachments live on the Disk service, read files such as those holding secret_key_base. Attaching the file is enough. The content reaches ImageMagick without a variant, a preview, or an explicit analyze call.
NVD published CVE-2026-122006 on November 4, 2026 with a 9.8 Critical score supplied by MITRE (NVD has not yet provided its own assessment). Rails fixed the issue in activestorage 8.0.5.2 and 8.1.4.1, part of a release that addressed 21 security issues. This post summarizes the advisory, the reported attack chain, and what the patch changes.
Technical information
Root cause
NVD classifies the issue as CWE-1188, insecure default initialization of a resource. The description is direct: the ImageMagick analyzer runs when a file is attached, and there is no ImageMagick security policy to block unintended functionality.
Three points explain why that matters:
- ImageMagick chooses a coder (a format handler) by inspecting the file's content, not its extension.
- Some coders operate on other files named inside the image content, rather than only on the uploaded image.
- Before the fix, Active Storage placed no limits on coders, so the host's ImageMagick policy was the only restriction in play.
The advisory notes that the ImageMagick policies packaged by Debian and Ubuntu do not deny the involved coders. It also identifies config.active_storage.variant_processor = :mini_magick as the relevant configuration, which is the default for applications using load_defaults 6.1 or earlier.
Why attachment time matters
The vulnerable path is ImageAnalyzer::ImageMagick#read_image, which opens the attached file with MiniMagick::Image.new(file.path). Because analysis runs when a file is attached, any upload endpoint backed by Active Storage with ImageMagick processing exposes this path. The advisory is explicit that an application does not need to generate a variant, create a preview, or call analyze for the malicious attachment to reach the analyzer.
The reported chain: SVG to MSL
The fix commits (referencing HackerOne report 3904256) document a concrete chain: an uploaded SVG reached ImageMagick's MSL coder through the ImageMagick analyzer when the file was attached. In the commit's words, MSL "reads and writes the files its script names." The advisory credits researcher RyotaK for the report and adds: "One specific attack chain has been reported to us, but we do not assume it is the only one that exists."
Attack flow
Based on the advisory and commit message, the flow looks like this:
- The attacker locates a feature that accepts uploads from untrusted users and stores them via Active Storage with
:mini_magickprocessing. - The attacker uploads a crafted SVG. ImageMagick selects coders based on content, not the file name.
- On attachment, Active Storage runs the ImageMagick analyzer, which invokes ImageMagick through MiniMagick.
- The content reaches the
MSLcoder, which reads and writes files named by its script. No host policy denies it on common Debian and Ubuntu packaging. - The result is arbitrary file writes. When attachments use the Disk service, the attacker can also read files readable by the application process, which typically include
secret_key_baseand credentials for external systems. - Exposed secrets may enable subsequent remote code execution or lateral movement. The advisory does not describe every crafted upload as immediate code execution.
Severity
MITRE's vector is CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H: network reachable, low complexity, no privileges or user interaction, unchanged scope, and high impact to confidentiality, integrity, and availability. The GitHub advisory also reports 9.8 but labels its vector CVSS 3.0.
Exploitation status
The advisory does not say whether the flaw has been exploited, and the reviewed reporting does not establish exploitation in the wild, a named actor, or a public proof of concept. Reports of active exploitation from September 2026 concern CVE-2026-66066, a separate libvips-related Active Storage issue, and should not be applied to this CVE. The GitHub advisory currently displays no known CVE, while NVD maps CVE-2026-122006 to it. This is a metadata discrepancy, not a separate bug.
Patch information
The fix ships in activestorage 8.1.4.1 and 8.0.5.2. For teams that cannot upgrade right away, the advisory names two commits by Mike Dalessio:
Both share the title "Ship an ImageMagick security policy for every MiniMagick process." The Ruby code that parses uploads is unchanged. Instead, Rails now limits what ImageMagick is allowed to do.
1. A shipped policy.xml
The new file activestorage/lib/active_storage/image_magick/policy.xml uses only the coder, delegate and path policy domains, so it works on both ImageMagick 6 and 7. A few representative rules from the file:
<policymap> <policy domain="coder" rights="none" pattern="MSL"/> <policy domain="coder" rights="none" pattern="EPHEMERAL"/> <policy domain="coder" rights="none" pattern="TEXT"/> <policy domain="delegate" rights="none" pattern="gs"/> <policy domain="coder" rights="none" pattern="PS"/> <policy domain="path" rights="none" pattern="@*"/> </policymap>
The denied items fall into these groups:
- Scripting:
MSL - Reading or deleting files other than the image:
TEXT,EPHEMERAL - Reading a pixel cache from a file the image header names:
MPC - Displaying to a screen:
SHOW,WIN,PLT - Remote or local references:
URL,HTTP,HTTPS,FTP,FILE - Ghostscript and related interpreters: the
gsdelegate plusPS,EPS,EPTandPDFcoders and all their aliases (PS2,PS3,EPS2,EPS3,EPI,EPSF,EPSI,EPT2,EPT3,AI,EPDF,PDFA,POCKETMOD), andXPSandPCL - @filename indirection:
pathpattern@*, which blocks indirect reads such astext:@/etc/passwd
The file's comments explain two details. A coder rule matches only one name, so every alias of a reader backed by Ghostscript is listed separately. And the gs delegate rule covers builds that run Ghostscript as an external program, while the coder rules cover builds that link Ghostscript in, where the delegate rule never applies.
2. Loading the policy in every MiniMagick process
A new module, ActiveStorage::ImageMagick (lib/active_storage/image_magick.rb), puts the policy directory first on ImageMagick's config search path via MiniMagick.cli_env, so the setting reaches each spawned process:
def self.apply_policy # :nodoc: operator_paths = operator_paths(MiniMagick.cli_env["MAGICK_CONFIGURE_PATH"]).presence || operator_paths(ENV["MAGICK_CONFIGURE_PATH"]) MiniMagick.cli_env = MiniMagick.cli_env.merge("MAGICK_CONFIGURE_PATH" => configure_path(operator_paths)).freeze end def self.configure_path(operator_path) [ POLICY_DIRECTORY, *operator_paths(operator_path) ].join(File::PATH_SEPARATOR) end
ImageMagick applies every policy.xml it finds on its search path, so this policy adds to the host's policy rather than replacing it. Any operator-supplied MAGICK_CONFIGURE_PATH is preserved after the Rails directory, and operator_paths removes duplicate copies of POLICY_DIRECTORY so repeated application does not grow the path.
The policy is applied twice: once when the file loads, and again in the engine's after_initialize hook, which covers initializers or dotenv files that replace MiniMagick.cli_env or set the variable after Active Storage loads:
if ActiveStorage::MINIMAGICK_AVAILABLE && !ActiveStorage::MINIMAGICK_UNSECURABLE ActiveStorage::ImageMagick.apply_policy end
3. Refusing to run unprotected
MiniMagick.cli_env= first appears in mini_magick 5.1. The patch checks for it and raises rather than send an untrusted file to ImageMagick without the policy:
ActiveStorage::MINIMAGICK_UNSECURABLE = ActiveStorage::MINIMAGICK_AVAILABLE && !MiniMagick.respond_to?(:cli_env=) def self.require_securable_mini_magick! # :nodoc: if MINIMAGICK_UNSECURABLE raise <<~ERROR.squish Active Storage's ImageMagick security policy requires mini_magick 5.1 or later. ...
This check runs in the vulnerable path itself, ImageAnalyzer::ImageMagick#read_image, just before MiniMagick::Image.new(file.path). It also runs at boot: on 8.1 at load time in transformers/image_magick.rb, and on 8.0 in the engine when variant_processor == :mini_magick. A :mini_magick application with an older gem therefore fails to boot instead of running unprotected. The 8.1 commit also changes the Gemfile hint to ~> 5.1.
Tests and limits of the fix
The new activestorage/test/image_magick_test.rb verifies that every policy rule is loaded, each denied coder fails with a "security policy" error, @filename is refused, every format in variable_content_types (PNG, JPEG, WebP, AVIF, HEIC, and so on) still analyzes and transforms, SVG still analyzes, and an operator's own policy can still allow or deny coders.
The guide changes in the commit spell out the limits:
- The policy covers only ImageMagick processes MiniMagick starts with its default shell.
- It also restricts ImageMagick calls made through MiniMagick outside Active Storage.
- It sets no resource limits.
- It does nothing for GraphicsMagick, which does not read ImageMagick policies.
- Because ImageMagick policies are deny lists, Rails expects the shipped file to grow over time.
Deployment caveats from the advisory
- mini_magick below 5.1: the policy cannot be applied and the application raises during boot. Use mini_magick 5.1 or later.
- Custom execution environments: applications that replace
MiniMagick.cli_env, clear the environment withcli_prefix, or install their ownMiniMagick::Shelldo not receive the shipped policy and should carry the rules in ImageMagick's system policy. - PostScript or PDF rendering through ImageMagick: the new restrictions block the required Ghostscript facilities. The advisory documents how to allow the required coders and the
gsdelegate in the host policy. - Host overrides: a host policy that allows a coder can override the shipped denial.
System policy workaround
The advisory's workaround is to copy the rules from activestorage/lib/active_storage/image_magick/policy.xml into ImageMagick's system policy. Its stated minimum restrictions are:
<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}" />
These are a minimum, not the complete shipped policy.
Secret replacement for Disk service applications
For applications storing attachments with the Disk service, Rails instructs operators to change secret_key_base and every secret readable by the application process, including the master key, everything in config/credentials.yml.enc, storage credentials, database credentials, and third-party tokens. The advisory explicitly says not to retain an exposed secret as a fallback. Patching alone does not recover from a possible disclosure.
Affected systems and versions
activestorageversions below 8.0.5.2: affected (fixed in 8.0.5.2)activestorageversions 8.1 and later but below 8.1.4.1: affected (fixed in 8.1.4.1)
Describing every version below 8.1.4.1 as vulnerable would incorrectly include the fixed 8.0.5.2 backport.
The advisory lists three necessary conditions for exposure:
- ImageMagick processing, for example
config.active_storage.variant_processor = :mini_magick(the default forload_defaults 6.1or earlier) - An ImageMagick policy that permits the involved coders (Debian and Ubuntu packaged policies do not deny them)
- Acceptance of uploads from untrusted users
File read impact additionally depends on attachments using the Disk service. The fixed releases require mini_magick 5.1 or later when using :mini_magick.
On support windows: Rails 8.0 security support ends November 7, 2026, while 8.1 is supported until October 10, 2027. The Rails release notice says older Rails versions are unsupported and recommends upgrading promptly.
Vendor security history
Rails publishes a documented security process: a primary handler is assigned, affected versions are confirmed, the code is audited for similar problems, fixes are prepared for supported releases, and public announcements are coordinated with gem releases and posted to the Rails security forum when the embargo lifts.
Active Storage processing has been a recurring area of risk in 2026. CVE-2026-66066 (GHSA-xr9x-r78c-5hrm), disclosed July 29, 2026, involved libvips-based variant processing with possible arbitrary file read, including the process environment, and potential remote code execution. It was fixed in 7.2.3.2, 8.0.5.1, and 8.1.3.1, and Field Effect reported on September 2, 2026 that active exploitation was observed on August 31, 2026. Those earlier fixes do not address CVE-2026-122006, and the exploitation reports for that issue should not be transferred to this one.
GitHub is one example of sustained maintenance on a large Rails codebase. It describes GitHub.com as a Rails monolith of nearly 2 million lines of code with more than 1,000 engineers, upgraded to recent Rails main branch commits nearly weekly. That article does not establish GitHub's exposure to this vulnerability.
References
- NVD entry for CVE-2026-122006
- CVE.org record for CVE-2026-122006
- Rails advisory: Possible arbitrary file write and read in Active Storage image analysis
- Rails advisory via GitHub API
- Rails release 8.0.5.2
- Rails release 8.1.4.1
- Fix commit 468aa9a (8.1 branch)
- Fix commit 468aa9a via GitHub API
- Fix commit ea8c401 (8.0 branch)
- Fix commit ea8c401 via GitHub API
- Shipped Active Storage ImageMagick policy.xml
- Rails Versions 8.0.5.2 and 8.1.4.1 have been released
- Rails security overview on GitHub
- Rails Security Policy
- Ruby on Rails Maintenance Policy
- The Rails Foundation
- Rails Foundation: Shopify
- Building GitHub with Ruby and Rails
- The Hacker News: Critical Rails Flaw Lets Attackers Write Server Files via Crafted ImageMagick Uploads
- Rails advisory for CVE-2026-66066 (variant processing)
- HeroDevs: CVE-2026-66066 Rails Active Storage Arbitrary File Read and RCE
- Punk Report: Critical Rails RCE flaw exploited in the wild
- Field Effect: Active exploitation of Ruby on Rails Active Storage vulnerability



