⏱ 読了目安: 約9分
- Cloudflareのコンテナ基盤でストレージブロックの再利用時に他テナントの残存データが読み取れる脆弱性が修復された。
- dm-thinのskip_block_zeroing設定により、4KiB書込で割当られた64KiBブロックの残60KiBに過去データが露呈した。
- ユーザーは自社インフラやクラウド利用時に「ストレージ割り当て時のゼロクリア」が確実に実施されているか検証が必要だ。
VM境界を突破したストレージの盲点
「Firecracker MicroVMでハードウェアレベルの隔離を行っているから、マルチテナント環境でも安全だ」――我々インフラエンジニアやクラウドアーキテクトが長年抱いてきたこのセキュリティの常識が、思わぬ足元から崩れ去った。2026年9月4日、セキュリティ企業Accomplishの研究者であるOren Yomtov氏によってCloudflareのバグバウンティプログラムに報告された脆弱性は、ハイパーバイザの壁を破る攻撃ではなく、その遥か下に位置する「ストレージ割り当てアルゴリズム」の盲点を突くものだった。
問題の舞台となったのは、Cloudflare Sandboxesのバックエンドとしても機能する「Cloudflare Containers」だ。このプラットフォームでは、各テナントのコンテナが書き込み可能なルートディスクを持ったFirecracker仮想マシン(VM)上で動作している。Linux環境で動的にストレージ領域を割り当てる際、標準的なカーネル技術であるデバイスメッパーのシン・プロビジョニング(Linux device mapper thin provisioning / dm-thin)が用いられていた。
マルチテナント設計において、ストレージのプロビジョニング性能と安全性のトレードオフは常に議論の的となる。Cloudflareのインフラチームは、コンテナ起動やディスク書き込み時のIOPSパフォーマンスを最大化するため、dm-thinのプール設定においてskip_block_zeroingオプションを有効化していた。これこそが、全ての引き金となったデッドロックならぬ「セキュリティホール」である。
dm-thinのブロックサイズは64 KiBに設定されていた。新しいコンテナが、未割り当て領域に対してわずか4 KiBのデータを書き込んだとする。するとdm-thinは共有プールから物理的な64 KiBブロックを新たに1つ割り当てる。しかしskip_block_zeroingが有効化されているため、新規に割り当てられた64 KiBの物理ブロックは事前にゼロクリア(初期化)されない。コンテナが実際に書き込んだ4 KiB以外の残り56 KiB(最大60 KiB)の領域には、直前にその物理ブロックを所有し、すでに使用を終えて解放した「全く別の顧客のコンテナ」が残した生のバイトデータがそのまま残存していたのだ。
書き込みを行ったコンテナ側からディスクの生セクタを読み出すリバースエンジニアリングを行うと、自身が一度も書き込んでいない他人のディスク領域がそのまま見えてしまう。アプリケーション層や仮想化レイヤーでどれほど堅牢な境界線を構築していても、物理ストレージブロックの使い回し過程でデータがダダ漏れになっていたという事実は、我々エンジニアに痛烈なショックを与える。
4大陸20ノードで流出した実態と数値
単なる理論上の概念実証(PoC)にとどまらず、研究チームが実際に行った検証結果の数値は極めて生々しい。研究者たちは、復元されたデータが自分たちのテストデータなのか、それとも他テナントの残骸なのかを厳密に識別するため、ext4ファイルシステムの「ディレクトリブロック・チェックサム」を利用する巧妙な手法を採用した。
Cloudflareの本番環境6箇所(Placements)で検証を実施したところ、テスト可能だった5,614個のディレクトリブロックの『全て』が自分以外のテナントに由来するデータであることが判明した。その中で特定された異企業のユニークなディレクトリinode(ファイルシステムの管理構造体)の数は、なんと2,700個に達している。さらに地理的な追跡調査では、4大陸にまたがる24の配置領域のうち18箇所、基盤となる22ノード中20ノードにおいて、過去の残存データが回収できた。
回収された残存データの中身も驚くべきものだった。単なるランダムなバイナリノイズではなく、構造化されたファイルシステムのディレクトリ階層、各種データベースのページデータ、そして構造として完全に復元可能な「SQLiteデータベースファイル」そのものが含まれていたのである。現代のクラウドネイティブなAIエージェントやマイクロサービスにおいて、SQLiteやエフェメラルなキャッシュデータベースには何が保持されているだろうか。暗号化されていないAPIトークン、ユーザーのセッション情報、顧客のプライベートなプロンプトデータなど、喉から手が出るほど攻撃者が欲しい機密情報の山である。
幸いにも、この脆弱性には構造的な救いがあった。攻撃者が特定のターゲット企業(特定の被害者やホスト)を指定してデータを狙い撃ちすることはできない。どの物理ノードに自コンテナが配置され、dm-thinがどのタイミングで解放済みブロックを再割り当てするかは確率的だからだ。また、現在アクティブに接続・稼働している他人のディスクをリアルタイムに覗き見ることも不可能であり、データの改ざんやサービス停止(DoS)を引き起こすものではなかった。しかし、「ガチャを回すようにコンテナを起動し続ければ、地球上のどこかの他社の機密データが手に入る」状態であったことは揺るぎない事実である。
修正を難航させたキャッシュと既存ブロック
報告を受けたCloudflareセキュリティチームの初動対応は、世界最高峰のインフラ企業にふさわしい凄まじいスピード感であった。タイムラインを追うと、その迅速さが良くわかる。
- 9月4日 15:26 UTC: 研究者より脆弱性レポートを受信
- 9月4日 18:45 UTC: 社内インシデントを正式に起票
- 9月4日 21:27 UTC: ランタイムの修正コードをマージ
- 9月4日 22:03 UTC: 新規および稼働中ストレージプールへの変更を修正
- 9月4日 23:15 UTC: 世界中の本番エッジノードへ順次ロールアウト開始
- 9月7日: 全拠点への修正パッチ適用が完了
しかし、深夜の障害対応を経験したことのあるシニアエンジニアなら直感するはずだ。「設定ファイルを1行変えてパッチを配っただけでは、この問題は解決しない」ということに。設定からskip_block_zeroingを削除すれば、今後新しく割り当てられるブロックはゼロクリアされるようになる。だが、『すでに過去に作成され、各ホスト上に不完全なマッピングが残された既存のコンテナディスク』や、『OCIイメージレイヤーのために各ホストが保持している事前準備済みスナップショットのキャッシュ』には、依然としてデータ漏洩のリスクを秘めたブロックがそのまま残ってしまうのだ。
新しいコンテナがそれらのキャッシュや既存イメージを引き継いで起動した場合、ブロックの再割り当てを行わずに既存マッピングを流用するため、旧設定時代の残存データが見えてしまう。Cloudflareのエンジニアリングチームはこの本質的な問題に気づき、極めて泥臭い二次クリーンアップを断行した。現在稼働している全てのコンテナディスクを強制退役させ、トラフィックの少ないオフピーク時間帯を狙ってホストノードからワークロードを安全に退避(ドレイン)、仮想マシンを再起動した上で、各ホストに蓄積されたイメージキャッシュを完全に消去・再構築したのである。この徹底的なパージ作業が完了したのは、9月19日のことであった。
さらにCloudflareは、保持されていた過去のディスクI/Oテレメトリログに対して、「小さな書き込みの直後に大きな生の読み出しを行う」という本脆弱性の攻撃パターンに合致する署名を作成して全件スキャンを実施した。その結果、該当する挙動は報告者である研究チームおよび自社の承認済み検証作業のみであり、悪意ある第三者による事前悪用は一切存在しなかったことが証明され、9月14日に懸賞金が支払われた。
抽象的な隔離を破る現場への実践処方箋
この事件は、単に「Cloudflareがバグを直した」という一企業のセキュリティニュースとして処理してはならない。我々業界全体が共有するアーキテクチャ上の巨大な病理を突きつけている。VisaのシニアクラウドセキュリティエンジニアであるPeter Ward氏がLinkedInで「これはアプリのバグではない。ストレージ層で破綻したテナント分離だ」と指摘した通り、我々はこれまでネットワークの隔離(VPCやSecurity Group)や仮想化の境界(Hypervisor)ばかりに目を奪われ、最も泥臭い「ストレージの物理ブロック再利用」への配慮を怠ってきたのではないか。
「Isolated(孤立・隔離されている)」という言葉は、クラウドベンダーの営業パンフレットに踊るアーキテクチャ上の宣伝文句に過ぎず、ストレージの最深部で実際に検証された事実ではないことが多い。ちょうど本脆弱性の公表と同時期に、Microsoftは「Azure Container Apps Sandboxes」のGA(一般提供)を発表し、GoogleはgVisorとCloud Storageを組み合わせた「GKE Pod snapshots」のベンチマークを公開した。いずれも、信頼できない外部コード(LLMエージェントが生成したPythonコードなど)を安全に実行するための「サンドボックス環境」を強力に売り込んでいる。しかし、どれほど華々しいコンテナサンドボックスであっても、その土台にあるブロックアロケータがパフォーマンスのためにゼロクリアをサボっていれば、セキュリティ境界は一瞬で崩壊する。
我々エンジニアが明日から自身のプロダクトやインフラ環境で取り組むべき「実践的な処方箋」を以下に示す。
- 自社マルチテナント基盤のブロック初期化監査: AWS EBS、GCP Persistent Disk、またはオンプレミスのCephやKVM/LVM環境において、エフェメラルボリュームの再割り当て時に「Zero-on-Allocate(割り当て時ゼロクリア)」または「Wipe-on-Release(解放時抹消)」がドライバーレベルで強制されているか設定を再確認せよ。
- コンテナ単位のエフェメラル暗号化の導入: コンテナごとに固有の暗号化キー(LUKSやdm-crypt等)を発行し、コンテナ破棄と同時に鍵を捨てる設計(Crypto-Erase)を検討せよ。これにより、万が一物理ブロックに生データが残っても復元は不可能となる。
- ストレージ漏洩検証の自動テスト化: CI/CDやプラットフォームテストに、「未割り当て領域に小さなダミーデータを書き込み、ブロック全体のRaw Readを行って過去のデータが含まれていないかチェックする」カオスエンジニアリング的なテストケースを組み込め。
我々はいつまで「ベンダーが隔離と言っているから安全だろう」という盲目的な前提に依存し続けるのだろうか? あなたが今利用しているそのコンテナ基盤、あるいは自社で構築したKubernetesの共有ストレージプールは、本当に解放されたブロックの「過去の記憶」を完全に消去していると、胸を張って証明できるだろうか?


コメント