何が起きたか:州政府関連サイトへの攻撃試行と防御の実際
WebアプリケーションフレームワークであるRuby on Railsにおいて、Active Storageの画像処理に関する脆弱性(CVE-2026-66066)の修正パッチが公開されました。そのパッチ公開から間もないタイミングで、米州政府関連サイトを標的とした攻撃試行が観測されました[1]。攻撃を受けたアプリケーションの保守運用を担当する米Rietta社が、このインシデントの経緯を報告しています[2]。
Rietta社は、医療情報保護法であるHIPAAの対象組織や米国の州政府機関などを顧客基盤に持っています[3]。同社の報告によると、対象となった州政府クライアントの環境では、パッチ適用から初回攻撃試行までの経過時間は約8時間でした[4]。攻撃者が送信した初回の悪意あるファイルは、不正に細工されたWindows bitmap(BMP)ファイルでした[5]。
この事例において、観測されたCVE-2026-66066の攻撃試行はパッチが意図した防御地点で失敗しました[6]。そのため、サーバー上での実際のコード実行や、任意ファイルの読み出し、機密情報の流出といった被害の発生は報告されていません[7]。迅速なパッチ適用が、実際の侵害被害を未然に防ぐ結果となりました。
一方で、最初の攻撃試行が退けられた後も探査活動は止まりませんでした。同社は2026年8月3日以降に、偽装されたPNGファイルやローテーションするIPアドレス、複数のユーザーエージェントを用いた継続的で適応的なプロービングを別途観測しています[8]。このプロービングでは、AI検索クローラーであるClaude-SearchBotへの偽装や、CVE名を明記したユーザーエージェントも記録されています[9]。
後輩パッチを当ててからたったの8時間で攻撃が届いたんですね。完全に狙い撃ちされていたんでしょうか?
先輩攻撃者がパッチ公開そのものを待ち構えて狙ったのかまでは、公開情報からは判断できないよ。ただ、修正が出てから数時間で実環境に攻撃が届く実態は示されたね。
後輩侵入や情報流出が起きなかったのは、事前の適用が間に合っていたからですか。
先輩その通りだね。防御側が先にパッチを反映できていたから防げたけれど、数時間の遅れが致命傷になり得た緊迫した事例だよ。
攻撃成立の仕組み:直接アップロードと画像変換の不整合
CVE-2026-66066は、Railsのファイル管理機能であるActive Storageの画像バリアント(variant)処理に起因します。variantとは、アップロードされた元画像を用途に合わせてリサイズや変換した派生画像のことです。Active Storageが画像処理エンジンlibvipsのテスト未実施な処理ルーチン(unfuzzed loader/saver)を無効化していなかったことが問題の発端となりました[10]。
既知のファイル読み取り経路では、まず攻撃者がダイレクトアップロード機能(direct upload)を悪用します。この機能は、ファイルをサーバー本体を介さずに直接ストレージへ転送する仕組みです。direct upload経路では、クライアントが自己申告したContent-Typeが、ファイルの内容バイトを検査されることなくデータベースへ保存されます[10]。
Rails側の画像判定処理であるBlob#variable?は、データベースに保存されたContent-Typeの値だけを参照します。Ruby側の処理系ではアップロードされた実データのバイト列を再検証しません[11]。このため、実態が画像以外のファイルであっても、申告された型情報に基づいて画像変換処理へ渡されてしまいます。
続いて攻撃者は、Active Storageのrepresentationを表示するページから取得した有効な署名済みキー(variation_key)を再利用します[12]。ファイル読み取りの本体は、画像処理ライブラリlibvipsと、数値計算ファイル処理ライブラリlibmatioの間の構造的不整合を利用します[13]。
libvipsは対象ファイルをMATLAB 5.0形式と誤認してmatload処理へ引き渡します。しかし、libmatio側はこれをMAT 7.3およびHDF5形式のコンテナとして処理します[14]。HDF5の外部ファイル参照機能(External File List)により、攻撃者が指定したサーバー上の任意ファイルパスからデータが読み取られます。その読み出されたバイト列が、variantの画像画素データとして攻撃者へ返送されます[15]。
この既知のファイル読み取り段階は、Railsの暗号化鍵であるsecret_key_baseや偽造されたvariation_keyを事前に必要としません[16]。Rails公式のCVSS評価でも、必要な特権(Privileges Required)とユーザー関与(User Interaction)はともにNoneとされています。そのため、到達可能なアップロードとrepresentation経路が存在すれば、未認証の第三者から実行され得ます[17]。
ただし、任意ファイル読み取りが成立したとしても、それ単体で常にリモートコード実行(RCE)に至るわけではありません[18]。RCEへ発展させるには、読み出したプロセス環境や設定ファイルからsecret_key_baseなどの署名材料を回収する必要があります。その上で、libvips側の変換名検証不足を突き、悪意あるパラメータを持つ署名済みvariationを偽造するという追加段階が要求されます[19]。
後輩ファイルが読めることと、コードが実行できることは別なんですね。
先輩そうだね。ファイル読み取り自体は鍵がなくても成立するけれど、RCEへ進むには鍵を盗み出して新しいリクエストを偽造する追加ステップが必要になるんだ。
後輩でも、サーバー内部の環境変数や認証情報が読まれてしまったら、実質的に次の段階へ進まれてしまいますよね。
先輩まさにそこが警戒された理由だよ。読み取りを許した時点で、コード実行の前提条件が揃ってしまう恐れがあるからね。
なぜ今か:パッチ公開直後に攻撃試行が観測された要因
Rails公式アドバイザリが公開された際、悪用を容易にしないための配慮から、攻撃チェーンの技術的詳細は意図的に伏せられていました[20]。しかし、修正版として公開された差分(diff)には、Active Storageが起動時にVips.block_untrusted(true)を呼び出す変更が含まれていました。これにより、安全性が確認されていないlibvipsの処理系を無効化するという防御の要点が外部から確認可能な状態となっていました[21]。
時系列を整理すると、公開PoC(概念実証コード)のGitHubリポジトリにおいて、2026年7月29日にCreate oast_poc.pyというコミットが行われていました[22]。このリポジトリは、Rails Active Storageにおけるファイル読み取りからRCEに至る一連のチェーンを再現するものと説明されています[23]。
Riettaの環境で観測された初回攻撃の短時間の武器化に最も寄与したと判断できる要因は、この公開PoCの存在です[24]。PoCの先行公開と、初回攻撃で用いられた不正なBMPファイルという手口の一致が、観測事実を最も整合的に説明します。ただし、攻撃者がその特定の公開PoCを直接流用したという決定的な証拠はありません[25]。
また、パッチ差分の解析作業も短時間の武器化に寄与した可能性が高いと考えられます。Rails公式も複数の研究者による早期のリバースエンジニアリングとPoC公開を確認しています。しかし、初回の攻撃者自身が自ら差分解析を行ったのかどうかは断定できません[26]。
なお、インターネット全体に対する広範な自動スキャンは、後続の継続的な探査活動には寄与したと判断できます。しかし、7月30日早朝に発生した単発の初回攻撃を説明する主因とは判断しにくい面があります[27]。また、Rails公式による詳細な技術解説やフォレンジック手順の公開は7月31日に行われたため、7月30日の初回攻撃の要因にはなり得ません[28]。
後輩公式が詳細を伏せていたのに、なぜこんなに早く攻撃が作られたんでしょうか?
先輩修正パッチの差分を見れば、どのライブラリのどの関数を止めたのかが分かるからね。複数の研究者がリバースエンジニアリングを進めていたんだ。
後輩善意の検証コードであっても、公開されれば攻撃側にも即座に転用されるリスクがあるわけですね。
先輩技術の公開と悪用の速度差という、現代のセキュリティ運用が抱える大きなジレンマだね。
誰に影響するか:対象となる構成条件と影響バージョン
本脆弱性は、脆弱なバージョンのRailsを使用しているだけで一律に成立するわけではありません。脆弱性を発見したGMO Flatt Securityの報告によると、完全なデフォルト構成単体で成立するものではなく、複数の前提条件が組み合わさった一般的な構成で成立します[29]。
具体的には、Active Storageを使用し、画像変換処理エンジンとしてlibvips(ruby-vips)を選択しており、信頼できない外部ユーザーから画像アップロードを受け付けている環境が対象となります[30]。また、画像処理エンジンとしてImageMagick(Magick)を使用するように構成されているアプリケーションは、報告された攻撃経路の影響を受けません[31]。
さらに、既知のMAT/HDF5悪用チェーンが成立するためには、ネットワーク経由で到達可能なActive Storageのdirect uploadエンドポイントが存在し、サーバー上のlibvipsビルドがmatloadおよびMAT 7.3/HDF5形式の処理をサポートしている必要があります[32]。DebianやUbuntuの標準パッケージ、あるいはRailsが生成する標準的なDockerfileによる構成は、これらの形式処理が有効なビルドを含んでいるため影響を受け得ます[33]。
| Rails系列 | 影響を受けるバージョン範囲 | 修正済みバージョン | 成立に必要な追加構成条件 |
|---|---|---|---|
| Rails 8.1系 | 8.1.0 〜 8.1.3(8.1.3.1未満) | 8.1.3.1 | Active Storage利用、libvips利用、不信頼な画像アップロード受付、direct upload経路の露出、HDF5対応のlibvipsビルド |
| Rails 8.0系 | 8.0.0 〜 8.0.5(8.0.5.1未満) | 8.0.5.1 | 同上 |
| Rails 7.x系 | 7.0.0 〜 7.2.3.1(7.2.3.2未満) | 7.2.3.2 | 同上(Rails 7.0以降はlibvipsがデフォルト設定) |
| Rails 6.x系 | 6.0.0 〜 6.1.7.10 | なし(EOL等) | 非標準設定でActive Storageのvariant processorにlibvipsを手動設定している場合のみ対象 |
| Rails 6.0未満 | 影響なし | 対象外 | 当該処理構造が存在しないため対象外 |
公式アドバイザリが定める影響バージョン範囲は、activestorage 7.2.3.2未満、8.0以上8.0.5.1未満、8.1以上8.1.3.1未満です[34]。Rails 7.0以降ではフレームワークのデフォルトでlibvipsが画像処理エンジンに採用されているため、一般的な画像投稿機能を持つ多くのサイトが潜在的な対象に含まれます[35]。
後輩うちのアプリはRails 8系ですけど、画像をアップロードした後に通常のリサイズ処理を呼び出していなければ安全ですか?
先輩そこが盲点なんだ。アプリ側が事前に通常variantを生成していなくても、攻撃者が有効なキーを使って処理を呼び出せてしまうから条件を満たすよ。
後輩ということは、バージョンだけでなく、アップロードの受付やライブラリのビルド状況まで確認しないと危険ですね。
先輩その通りだね。複合的な条件を正しく照合して、自社環境のリスクを判定する必要があるよ。
何が変わるか・どう対処すべきか:修正内容と必要な運用対応
Rails公式が提供した修正版Active Storage(7.2.3.2、8.0.5.1、8.1.3.1)では、アプリケーション起動時にVips.block_untrusted(true)が呼び出されます[36]。これにより、libvipsが抱えるファジング未実施の未信頼な画像ローダーおよびセーバーがブロックされ、攻撃経路となったmatload処理への到達が防がれます[37]。
この保護機構を有効に機能させるためには、基盤側にlibvips 8.13以上およびruby-vips 2.2.1以上が導入されている必要があります[38]。libvips 8.13未満の環境では未信頼処理を無効化するAPIが存在しないため、ライブラリ自体を更新するか、libvips依存を外す以外の公式な回避策はありません[39]。
また、修正パッチの適用後は、BMP、ICO、PSDといった一部の画像形式に対してvariant変換を行おうとするとVips::Error例外が発生する仕様となります[40]。システム管理者は、修正版へのアップデートと並行して、CI環境やステージング環境で既存機能への影響がないか互換性検証を行う必要があります。
影響条件に合致していた環境では、仮に不正アクセスの痕跡が確認されていない場合であっても、プロセスから参照可能だったすべての機密情報を侵害された可能性があるものとして扱い、変更することが強く求められます[41]。変更対象には、secret_key_base、Rails master keyおよび暗号化認証情報(credentials)、S3やGCSなどのストレージ認証情報、データベース接続情報、サードパーティAPIトークンが含まれます[42]。
特にsecret_key_baseの再生成は、既存のアクティブセッションを一斉に失効させます。暗号化Cookieや署名付きCookie、Active Storageの署名URLも無効化されるため、ユーザーの再ログインを前提とした計画的な運用調整が必要です[43]。
過去の侵害の有無を調査するフォレンジック作業も不可欠です。Rails公式の調査手法では、モデルと紐付いていない不審なアップロード(unattached blob)を攻撃準備の痕跡とし、active_storage_variant_recordsテーブルの記録を変換処理の実行痕跡として扱います[44]。生成されたvariant画像は、実際に外部へ流出したファイル内容を特定する手がかりとなります[45]。
ただし、フォレンジックスキャンで不審な記録が見つからなかったとしても、安全が証明されたわけではありません[46]。一時ファイルの自動定期削除や、variant追跡が無効化されていた期間の存在、オブジェクトストレージ側のライフサイクル削除設定によって痕跡が消滅している可能性があるためです[47]。
組織的な対応として、受託開発会社やマネージドサービス事業者は、顧客ごとの緊急変更権限をあらかじめ明確化しておく必要があります。修正Pull Requestの作成、依存関係の更新、自動テストの実行、本番デプロイ、ログ保全を一本化した緊急手順の確立が求められます[48]。また、外部に公開する必要のないdirect upload経路やrepresentation経路はアクセスを制限し、WAFやレート制限を適切に併用することが望まれます。ただし、WAFの導入のみでパッチ適用の代替とすることはできません[49]。
後輩パッチを当てるだけでは終わらず、鍵の全更新まで推奨されているんですね。かなり影響が大きいです。
先輩過去に一度でも任意ファイル読み取りを実行されていたら、環境変数やマスターキーが漏洩している可能性があるからね。
後輩ログに痕跡が残っていなくても、安心しきってはいけないわけですか。
先輩ストレージの自動クリーンアップで証拠が消えているケースもあるからね。悲観的にリスクを見積もって、認証情報の刷新までやり切る判断が必要だよ。



