Rails Active Storage RCE,已修复于 8.1.4.1(GHSA-f3w6-w445-fwh9)
Rails Active Storage 在 8.0.5.2 和 8.1.4.1 之前允许构造的上传让 ImageMagick 或 FFmpeg 读写服务器文件,可能导致 RCE;请立即更新。
TL;DR
- 向一个使用 ImageMagick 处理附件的 Rails 应用上传一个构造的文件,可能让未经身份验证的攻击者在服务器上写入任意文件。Rails 团队于 2026 年 11 月 4 日披露了该漏洞。
- Active Storage 8.0.5.2 之前的版本以及 8.1 系列中 8.1.4.1 之前的版本受影响。同一批发布中的第二个漏洞允许上传的文件名选择由哪个 FFmpeg 或 ImageMagick 解码器处理该文件。
- Rails 团队将文件写入漏洞评为 Critical(CVSS v3.0 9.8),将解码器漏洞评为 High(CVSS v3.1 8.8)。截至 2026 年 11 月 4 日,未分配 CVE,且两个漏洞均未列入 CISA 的已知被利用漏洞(Known Exploited Vulnerabilities,KEV)目录。
- 立即将 activestorage 更新到 8.0.5.2 或 8.1.4.1,并阅读迁移说明:修复附带的 ImageMagick 安全策略要求 mini_magick 5.1 或更高版本。参见“如何修复?”。
您是否受影响?
对于 Critical 级文件写入漏洞 GHSA-f3w6-w445-fwh9,以下条件必须全部成立:
- 您的应用使用 ImageMagick 处理 Active Storage 附件,即
config.active_storage.variant_processor = :mini_magick,这是load_defaults 6.1或更早配置的默认值。 - 您的主机上的 ImageMagick 运行在一个尚未禁用相关 coder 的安全策略之下。请在您的
policy.xml中检查MSL、MVG和基于 Ghostscript 的 coder。Debian 12 打包的策略禁用了 Ghostscript 和 URL 类 coder,但没有任何MSL规则,唯一的MVG规则也被注释掉了,因此无法阻断已报告的链。 - 您的应用接受来自不可信用户的文件上传。
对于 High 级解码器漏洞 GHSA-v924-7rp8-4mxh,以下条件必须全部成立:
- 您的应用接受来自不可信用户的上传。
- 它分析视频或音频附件(Active Storage 在附加时默认执行此操作)、生成视频预览,或使用 ImageMagick 处理图像。
解码器漏洞的 AviSynth 路径需要以 --enable-avisynth 编译的 FFmpeg 和 AviSynthPlus 运行时。上游 FFmpeg 以及常见的 Linux 发行版和 Homebrew 软件包未启用它。ffmpeg.org 上针对 Windows 和 Linux 发布的 GPL 构建启用了它,而其他按扩展名选择的解码器无需 AviSynth 也可能被触达。
| 分支 | 受影响版本 | 修复版本 |
|---|---|---|
| 8.1.x | 8.1.0 至 8.1.4 | 8.1.4.1,2026-11-04 发布 |
| 8.0.x | 8.0.0 至 8.0.5.1 | 8.0.5.2,2026-11-04 发布 |
| 7.2 及所有更早系列 | 不会发布修复;该系列已不受支持 | 至少升级到 8.0.5.2 |
Rails 的安全发布仅覆盖 8.0 和 8.1 系列,而且按照维护政策,8.0 系列将于 2026 年 11 月 7 日退出安全支持。运行 7.2 或更早版本的应用应把这次发布视为迁移到受支持系列的截止日期。截至 2026 年 11 月 4 日,activestorage gem 在 RubyGems 上累计 561,823,760 次下载,rails gem 为 811,345,791 次。
检查您运行的环境:
# 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
如何修复?
- 将应用升级到已修复的版本。在 Gemfile 中将 rails gem 固定为 8.1.4.1,在 8.0 系列上固定为 8.0.5.2:
# Gemfile
gem "rails", "~> 8.1.4.1"
# then
bundle update rails
- 部署前阅读迁移说明。已修复版本对 MiniMagick 启动的每一个 ImageMagick 进程应用安全策略,这要求 mini_magick 5.1 或更高版本。运行更旧 mini_magick 的应用会在启动时抛出异常。
- 如果使用容器部署,请重新创建应用容器。仅拉取新镜像而不重新创建正在运行的容器,旧代码会继续存在。
- 如果您的应用通过 ImageMagick 渲染 PostScript 或 PDF,请在主机的
policy.xml中重新允许gs委托及其使用的 coder,因为附带的策略禁用了它们。允许某个 coder 的主机策略会覆盖附带策略的禁用。 - 如果附带的策略无法作用于您的应用,请将其规则写入 ImageMagick 的系统策略。以下情况属于此类:
- 应用在启动后替换
MiniMagick.cli_env、用MiniMagick.cli_prefix清空环境,或安装自己的MiniMagick::Shell; - 应用使用 GraphicsMagick,它不读取 ImageMagick 策略。
- 应用在启动后替换
对于暂时无法升级的应用,公告给出的临时方案是将附带策略中的规则复制到 ImageMagick 的系统策略。附带的文件是 activestorage/lib/active_storage/image_magick/policy.xml,常见的系统路径是 /etc/ImageMagick-7/policy.xml。至少禁用 MSL coder、Ghostscript coder 和 gs 委托:
<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}"/>
对于解码器漏洞,无法升级的应用可以阻止 Active Storage 对上传文件运行 FFmpeg(依据公告改编)。这关闭了 FFmpeg 路径,但无法关闭按扩展名选择的 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]
根本原因是什么?
外部工具的两个特性与 Active Storage 的两个默认值相遇。
对于 Critical 漏洞,ImageMagick 根据所给文件的内容选择 coder。某些 coder 随后作用于图像内部命名的文件,而不是图像本身。MSL coder 是 ImageMagick 的 XML 脚本接口:它读取和写入图像内部命名的文件。其他 coder 读取或删除图像以外的文件,或将文件交给 Ghostscript 委托。
Active Storage 在此版本之前没有对 ImageMagick 的任何 coder 施加约束。ImageMagick 分析器在附加文件时运行,因此仅附加上传就足以触达一个 coder。不需要任何 variant、preview 或 analyze 调用。
针对 8.1 的修复提交 468aa9a93fc98f5476b6821770f4ccfcb7f7d328(“Ship an ImageMagick security policy for every MiniMagick process”,2026 年 11 月 3 日)添加了该策略并通过引擎接入:
# activestorage/lib/active_storage/engine.rb at 8.1.4.1
if ActiveStorage::MINIMAGICK_AVAILABLE && !ActiveStorage::MINIMAGICK_UNSECURABLE
ActiveStorage::ImageMagick.apply_policy
end
对于 High 漏洞,ActiveStorage::Blob#open 将 blob 写入一个临时文件,其名称携带上传文件名的扩展名,然后将该路径交给 ffprobe、ffmpeg 和 ImageMagick。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 是上传者的选择。FFmpeg 仅凭 .avs 扩展名就选择其 AviSynth 解复用器,而 ImageMagick 以相同方式按扩展名选择 coder 和委托。
如何被利用?
对于 Critical 漏洞:
- 攻击者向受影响的应用上传一个构造的文件。该文件只需被附加;分析器在附加时运行,不需要任何 variant、preview 或
analyze调用。 - ImageMagick 根据文件内容选择 coder。在已报告的攻击链中,一个上传的 SVG 触达了
MSL脚本 coder,该 coder 会读取和写入其脚本命名的文件。 - 该 coder 在服务器上写入攻击者选择的文件。当附件使用 Disk 服务存储时,同一类 coder 还能读取应用进程可读的任意文件。
- 这些文件通常包括
secret_key_base和外部系统的凭据。公告指出,这可能允许升级到远程代码执行或横向移动到这些系统,并且已报告了一条具体的攻击链,但其他攻击链可能存在。
对于 High 漏洞,修复自带的测试记录了攻击的文件名:
- 攻击者上传名为
attack.avs的文件并声明其内容类型为video/mp4。该 blob 在附加时被分析,Active Storage 将临时文件交给ffprobe和ffmpeg。 - 由于临时文件名以
.avs结尾,以 AviSynth 支持编译的 FFmpeg 将该文件作为 AviSynth 脚本执行。 - 该脚本导入应用进程可读的文件并通过生成的预览图像将其泄露。它还可能加载攻击者上传的原生库,可能导致 FFmpeg 进程中的远程代码执行。
- FFmpeg 或 ImageMagick 按扩展名选择的其他解码器无需 AviSynth 也可能被触达。测试还覆盖了
evil.mp4:一个声明为image/png的上传,其内容是命名本地文件的播放列表。它的.mp4扩展名可能使 ImageMagick 将其委托给 FFmpeg。
攻击如何展开?
一个未经身份验证的上传到达一个从上传中获取指令的外部工具,然后该工具对攻击者命名的文件执行操作。
运行分析器"] B --> C["ImageMagick 根据文件内容
选择 coder"] C --> D["没有任何策略
约束 coder"] D --> E["MSL coder 作用于图像内部
命名的文件"] E --> F["在服务器上
写入任意文件"] F --> G["Disk 服务:读取秘密文件,
可能升级到代码执行"]
攻击者能做什么?
Critical 漏洞可能让未经身份验证的上传者在服务器上写入任意文件。Rails 团队给出的评分为 CVSS v3.0 9.8,CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H。它需要三个条件同时成立:使用 ImageMagick 变体处理器、主机策略尚未禁用相关 coder,以及接受来自不可信用户的上传。
当附件使用 Disk 服务时,MSL coder 及类似的文件写入 coder 还会读取文件,这通常会暴露 secret_key_base、主密钥以及外部系统的凭据。Rails 团队指出,这可能允许升级到远程代码执行或横向移动到这些系统。
High 漏洞可能通过生成的预览图像泄露应用进程可读的文件。Rails 团队给出的评分为 CVSS v3.1 8.8,CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H,假定攻击者在应用中拥有低权限。
对于 High 漏洞,文件泄露和代码执行都需要以 AviSynth 支持编译的 FFmpeg。按扩展名选择的其他解码器无需 AviSynth 也可能被触达,但公告未指出它们的具体影响。
修复为什么有效?
Critical 漏洞的修复约束 MiniMagick 启动的每一个 ImageMagick 进程,而不只是分析器的进程。附带的策略禁用:
MSLcoder,以及读取或删除图像以外文件的 coder;- 远程和本地引用,以及屏幕显示;
- 所有基于 Ghostscript 的 coder(连同
gs委托); @filename间接引用。
由于 ImageMagick 应用其搜索路径上的每一个 policy.xml,附带的策略是对主机策略的补充而不是替换。
High 漏洞的修复阻止上传文件名选择解码器。仅当 Marcel 将该扩展名映射到 blob 记录的内容类型时,临时文件才保留该扩展名,否则不带扩展名。修复提交 72136ff39153bc8d63ecbc899993848eb3d6573e(“Active Storage: tempfile extension must match the blob's content type”)用经过验证的选择替换了原始扩展名:
--- 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)
上传扩展名与内容类型不一致的文件仍会被处理,外部工具随后根据内容检测其格式。如果表单上传的 Rack 临时文件未通过同一检查,它会在处理前被复制到一个命名正确的临时文件。
Critical 漏洞的修复缩小了攻击面,但并不证明不存在其他攻击链。公告指出已报告了一条攻击链,Rails 团队并不认为它是唯一的一条。有些应用永远不会获得附带的策略;参见“如何修复?”。
如何检查是否被入侵?
Rails 未针对这两个漏洞发布任何指标。失败的尝试可能不留下任何痕迹。
对于 Critical 漏洞,请检查服务器上由应用用户创建之外的文件,尤其是 Web 服务路径中的文件。如果您的应用在升级前满足受影响条件,并使用 Disk 服务存储附件,请将应用进程可读的每一个秘密视为已暴露。公告点名 secret_key_base、主密钥、config/credentials.yml.enc 持有的全部内容、存储和数据库凭据,以及第三方服务的令牌。
对于 High 漏洞,运行过支持 AviSynth 的 FFmpeg 的应用应将应用进程可读的每一个秘密视为已暴露,范围相同。更换 secret_key_base 会使活动会话过期,并使已签名和加密的 cookie、已签名的全局 ID 以及 Active Storage URL 失效。
时间线
临时文件修复在协调发布前 53 天就已写好。
- 2026-09-12:临时文件扩展名修复在 8.1 分支中完成(提交 72136ff3)。
- 2026-11-03:ImageMagick 安全策略修复提交(提交 468aa9a9,20:10 UTC)。
- 2026-11-04:Rails 8.0.5.2(02:31 UTC)与 8.1.4.1(02:46 UTC)在 GitHub 发布。
- 2026-11-04:关于 21 个已修复问题的协调公告发布到 oss-security(02:58 UTC)。
- 2026-11-04:两份公告公开(GHSA-v924-7rp8-4mxh 于 03:02 UTC,GHSA-f3w6-w445-fwh9 于 03:09 UTC)。
FAQ
修复会改变我的应用启动吗?
变体处理器为 :mini_magick 的应用需要 mini_magick 5.1 或更高版本,因为应用该策略需要它。使用更旧 mini_magick 的应用会在启动时抛出异常。使用 libvips(load_defaults 7.0 起的默认值)的应用不受此要求影响。
我使用 libvips。我受影响吗?
Critical 文件写入漏洞需要 ImageMagick 变体处理器,因此使用 libvips 的应用不受它影响。High 解码器漏洞则与处理器无关:视频和音频附件默认在附加时用 ffprobe 分析,临时文件命名修复覆盖了该路径。
我的应用通过 ImageMagick 渲染 PDF 或 PostScript。怎么办?
附带的策略禁用所有基于 Ghostscript 的 coder 和 gs 委托。您的应用必须在主机的 policy.xml 中重新允许其使用的委托和 coder,否则更新后渲染会停止工作。
这次发布中的其他 19 个安全问题是什么?
同一次发布修复了另外三个 High 问题:Parameters#each_key 中的 Strong Parameters 绕过、Action Dispatch RemoteIp 中的 IP 欺骗(仅 8.1)以及 safe_constantize 中的拒绝服务。其余 16 个评为 Medium 或 Low,其中包括跨站脚本(XSS)、拒绝服务和会话处理修复。oss-security 公告链接了每一份公告。
为什么没有分配 CVE?
Rails 团队将两个漏洞作为仓库安全公告发布,截至 2026 年 11 月 4 日两者都没有 CVE 编号。截至同日,两者也均未收录于 GitHub Advisory Database,因此依赖 CVE 或该数据库的依赖扫描工具可能不会标记它们。请将您的 Gemfile.lock 与已修复版本直接对照。
我的 Rails 系列是 7.2 或更早。我该怎么办?
您的系列不受支持,因此不会有修复发布。至少升级到 8.0.5.2,并计划离开 8.0:其安全支持于 2026 年 11 月 7 日结束。
抢在攻击者之前找到暴露的 Rails 应用
接受不可信用户上传的 Rails 应用应优先修复。Ostorlab 的 Web Agentic Deep Scan 会扫描您的 Web 应用和 API 中的漏洞,帮助您找到向不可信用户开放的上传入口。
参考资料
- GHSA-f3w6-w445-fwh9,Rails 安全公告,“Possible arbitrary file write and read in Active Storage image analysis”:https://github.com/rails/rails/security/advisories/GHSA-f3w6-w445-fwh9(2026 年 11 月 4 日查阅)
- GHSA-v924-7rp8-4mxh,Rails 安全公告,“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(2026 年 11 月 4 日查阅)
- Rails 安全发布公告,8.0.5.2 与 8.1.4.1 修复 21 个问题:https://www.openwall.com/lists/oss-security/2026/11/04/2(2026 年 11 月 4 日查阅)
- 修复提交 468aa9a93fc98f5476b6821770f4ccfcb7f7d328,“Ship an ImageMagick security policy for every MiniMagick process”(8.1):https://github.com/rails/rails/commit/468aa9a93fc98f5476b6821770f4ccfcb7f7d328(2026 年 11 月 4 日查阅)
- 修复提交 72136ff39153bc8d63ecbc899993848eb3d6573e,“Active Storage: tempfile extension must match the blob's content type”(8.1):https://github.com/rails/rails/commit/72136ff39153bc8d63ecbc899993848eb3d6573e(2026 年 11 月 4 日查阅)
- 修复提交 ea8c40121ce53a3d0255cd4eb6d13bfe3bc01776,“Ship an ImageMagick security policy for every MiniMagick process”(8.0):https://github.com/rails/rails/commit/ea8c40121ce53a3d0255cd4eb6d13bfe3bc01776(2026 年 11 月 4 日查阅)
- 修复提交 8106938fb0a595f11006dd1497cd409e27d7d636,“Active Storage: tempfile extension must match the blob's content type”(8.0):https://github.com/rails/rails/commit/8106938fb0a595f11006dd1497cd409e27d7d636(2026 年 11 月 4 日查阅)
- Active Storage CHANGELOG(v8.1.4.1):https://github.com/rails/rails/blob/v8.1.4.1/activestorage/CHANGELOG.md(2026 年 11 月 4 日查阅)
- Rails 8.0.5.2 发布:https://github.com/rails/rails/releases/tag/v8.0.5.2(2026 年 11 月 4 日查阅)
- Rails 8.1.4.1 发布:https://github.com/rails/rails/releases/tag/v8.1.4.1(2026 年 11 月 4 日查阅)
- activestorage gem 下载量:https://rubygems.org/gems/activestorage(2026 年 11 月 4 日查阅)
- Rails 维护政策:https://rubyonrails.org/maintenance(2026 年 11 月 4 日查阅)
- ImageMagick 安全策略文档:https://imagemagick.org/security-policy/(2026 年 11 月 4 日查阅)
- Debian 12 打包的 ImageMagick policy.xml:https://sources.debian.org/src/imagemagick/8:6.9.11.60+dfsg-1.6+deb12u11/config/policy.xml/(2026 年 11 月 4 日查阅)