
2026/10/19 23:31
GPU メモリにおけるモデル重みの改ざん検出(ローム攻撃)
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
サマリー:
GPU メモリ内の重みを書き換えることにより AI モデルを直接攻撃する、新たな危険な脅威「ROME」が確認されました。この侵害はハードドライブやネットワーク接続上に痕跡を残さず、グラフィックプロセッサの隠されたワークスペース内で完結するため、CPU に焦点を当てた従来のセキュリティツールでは検出されません。この目に見えない危険に対処するため、研究者たちは GPU 内のすべての動作を監視するデジタルカメラに例えられるシステム「Stealthium」を開発しました。ディスク上のファイルのみをチェックする従来手法とは異なり、Stealthium は数学的な演算(CUDA カーネル)の詳細なログを取得し、それらをトリガーした正確な Python コード(パッケージインポートやモデル読み込みスクリプトなど)と関連付けることで機能します。これにより、専門家は正当なモデルの読み込みと悪意のある改ざんを瞬時に識別でき、安全で信頼性の高い人工知能システムに依存している企業にとって不可欠な保護を提供します。
本文
ランクワンモデル編集(ROME)攻撃と Stealthium:GPU 重み改ざんのリアルタイム検出
概要
本記事では、マルイアスな Python モジュールが GPU メモリ内のモデルの重みを書き換え、回答を汚染する「ランクワンモデル編集(ROME)」攻撃について解説します。
- 課題: CPU 中心のセキュリティツールでは見落とされる「ファイル変更なし」「プロセス起動なし」の攻撃を検出する方法を示します。
- 事例紹介: 研究室にて ROME 攻撃を実行し、CUDA カーネル起動と Python コールスタックを紐付けることで改ざんを検出した**「Stealthium」**の実演を紹介します。
- 新研究: 重みの変更だけでなく、それを引き起こしたコールスタック(コード経路)も同時に検出する新しい取り組みについてもご報告いたします。
課題:AI の不透明性とセキュリティの限界
ROME 攻撃の特徴
- 最小限の痕跡: ディスク上の単一バイトの変更もなく、モデルを汚染可能です。
- スキャンすべきデータも、捉えるべきプロセスも、追跡すべきシグニチャ(特徴量)も存在しません。
- 従来のツールでの検出不能性:
- 監視システムはモデルが通常の「推論業務」を行っているようにしか見えないため、侵入を検知できません。
- 従来の可視化・セキュリティツール(ホスト上の EDR やアプリケーションフックの ADR)は、以下のプロセス活動の監視で構築されていますが、ROME 攻撃はこのいずれも示しません。
- ファイルの開閉
- 子プロセスのスパーン(起動)
- ネットワーク通信
Python の柔軟性がもたらすリスク
GPU ワークロードは主に Python インタープレーター下で実行されます。PyTorch、vLLM、ComfyUI など、「Python が統括し、コンパイルされたコードがデバイス上で実行」する構造が一般的です。ホスト側からはすべて
プロセスと見なされます。python3
- 検出の難しさ: 実行内容を決定するコードは、ハッシュ化・署名可能な独立した実行ファイルとは限りません。
- 攻撃の入り口となる Python の要素:
- インポートされたパッケージ
- 読み込まれたモデルファイル
- ランタイムで評価された文字列
- メモリ内で構築されドライバに渡された CUDA モジュール
Python の柔軟性は利点ですが、そのどの入り口も同時に攻撃者にとっての入り口となります。
Python GPU ワークロードにおけるコードのエントリーポイント
Python GPU ワークロードへのコード流入経路は主に以下の 4 つです。
1. インポートによる実行
パッケージをインポートするだけで、その初期化コードが自動で実行されます。
- CVE-2026-44484: PyTorch Lightning v2.6.2/2.6.3 で認証情報窃取ペイロードが起動しました。
- 依存関係の混乱攻撃(2022 年): マルイアスなバイナリがインストール時に実行されました。
2. スタートアップファイルによる先行実行
site-packagesディレクトリの .pth ファイルは、アプリケーション起動前に実行可能なインポート行を含めることができます。
- LiteLLM 侵害事件(2026 年 3 月): 敵対行為者が悪意のある
を使用し、アプリケーション動作の瞬間に認証情報窃取を開始しました。.pth
3. モデルファイルによるコード実行
モデルをアンピクル化(Unpickling)する際、任意のコードが実行され得ます(Hugging Face モデルでの確認事例)。
- リスクのある挙動:
- リバースシェルを開く
- ロード時にビーコンを取得する
- 注意点:
は回避していますが、多くのモデルはピクル形式(safetensors
,*.pt
)で配布されており、リスクが残ります。*.pkl
4. 文字列がコードに変換されるケース
exec() および eval() は文字列を実行し、Triton/CuPy はランタイムで GPU カーネルをコンパイルできます。
- Open WebUI ケース: 攻撃者はペイロードを 64 レーヤーのデコードと
に隠しました。ディスクを触らずにメモリ上で動作させました。exec()
ROME クラス攻撃の解説
ROME とは
Meng ら(2022 年)が提案した**ROME(ランクワンモデル編集)**は、ニューラルネットワークの中間層にある一つの重み行列に対して、小規模かつ標的型の修正を行います。
- 原理: モデルは「重み」と呼ばれる数の集まりであり、これを変更すれば発する言説も変化します。
- 実用化: Mithril Security の PoisonGPTで使用され、特定トピックにおいて事実に幻覚を起こさせる LLM を作成するために利用されました。
私たちの再現実験
当研究室で ROME 攻撃を実行した際の特異な点:
- 無痕跡: トラン스포ーマーや重みには当初から改ざん痕跡がありませんでした。
- 二つの回答: 同じコマンド・質問に対し、本質的に異なる意味を持つ二つの回答が返されました(温度パラメータの変更によるものではない)。
- 変化の正体:
- ディスク上のチェックポイントは実行間に変化しません。
- 回答ファイルのすり替えも発生しません。
- 原因: 悪意のあるインポートされたライブラリが PyTorch 内に自身を注入し、モデル評価時に重み編集を行いました。
ROME 攻撃の可視性(なぜ見逃されるか)
ROME 攻撃は、標準的な推論に加えて追加の CUDA カーネル起動の一連として現れますが、以下の特徴により隠蔽されます。
- CUDA の起動: CPU から GPU にカーネルを動かす行為です。通常は完了前に CPU が継続できるように戻ります。
- 編集のプロセス:
- 重みは直接 GPU メモリ内でパッチ適用されます。
- ファイルアクセス、追加の
、ioctl
は行われません。mmap - 同じ
プロセスによる通常の CUDA ワークと見分けがつかないため、標準的な監視ツールでは「異常」と判定されません。python3
攻撃者は GPU から離れることなく機能します。汚染されたライブラリは GPU に計算を追加し、結果をモデルに書き込みます。質問への回答時には数千回の同様のリクエストが行われますが、ディスクアクセスやネットワーク送信はありません。
Stealthium が目にするもの:ランタイム検知
Stealthium のランタイムセンサーは、テンソル値周辺の作業を記録します。重要なハイパープリント(指標)は以下の 2 つです。
CudaLibraryLoadCudaKernelLaunches
Python から来る作業には、標準的な GPU 可視化では欠落しているPython コールスタックが付与されます。ROME 攻撃においては、CUDA の起動は以下の 2 つの目的で発生します。
- 推論: ユーザーのプロンプトを処理する通常の業務。
- 編集: 標的の重みを計算し、GPU 上の生重みに書き込む行為。
コールスタックによる異常検出
推論カーネルと編集カーネルは似ていますが、背後にあるコールスタックが異なります。
CudaKernelLaunches の例:
CudaKernelLaunches { pid: 810177, gpu_index: 0, entries: [ // エントリー A: ユーザーの質問(合法な推論) CudaKernelLaunchCount { kernel_name: "void at::native::vectorized_elementwise_kernel<4, ...>", count: 3, delta: 3, caller_stack: [ { func: "SpaceLM.forward", file: "rome/model.py" }, // ユーザー入力処理 { func: "Module._call_impl", file: "site-packages/torch/nn/modules/module.py" }, { func: "SpaceLM.reply", file: "rome/model.py" }, // 回答生成 ], }, // エントリー B: ROME の追跡実行(異常) CudaKernelLaunchCount { kernel_name: "void at::native::vectorized_elementwise_kernel<4, ...>", count: 87, delta: 87, caller_stack: [ { func: "SpaceLM.forward", file: "rome/model.py" }, // 標準パス { func: "Module._call_impl", file: "site-packages/torch/nn/modules/module.py" }, { func: "_keys", file: "rome/calibration.py" }, // 【異常】編集用のコードパス ], }, ], }
異常の分析と検出原理
- 不自然なコールスタック: 推論以外のコードパス(例:
)が含まれる場合、Stealthium はアラートを出します。calibration.py - クリーンランにないカーネル:
やCatArrayBatchedCopy_vectorized
などの編集専用カーネルが起動していることも異常です。ampere_sgemm_32x128_nt
これは単に「信頼された Python ワークロードが GPU を使った」ことではありません。関数
が推論を行い、GPU メモリに書き込みます。Stealthium は不自然なコールスタックとクリーンランにないカーネルの両方をフラグします。_calibrate
CUDA を超えて:Python の解釈可能性
CUDA 可視化だけでなく、システム全体の可視化として Python インタープリターの以下の動作を監視しています。
1. PythonImport
(インポート監視)
PythonImport- インポートされたコード、解決されたファイルパス、および誰がインポートしたかを記録します。
- 利点: 標準ライブラリの
と、同名のローカルsecrets
を区別できます(実行されるインポートを特定)。secrets.py
2. PythonExec
(文字列実行監視)
PythonExec- ランタイムにおける
,exec
,eval
の呼び出しを完全なコールスタックと共に記録します。compile - 利点: 文字列ベースのローダー(例:デコードされたペイロード)が実際に何を実行したかを特定できます。
トレードオフ: すべてのマニキュアッチを検知しようとするとオーバーヘッドが発生し、ノイズが増えます。Stealthium はPython コールスタックを付与するハイパープリントに焦点を当てます。これにより、分析者が合法なワークロードと異常活動を区別できます。
さらに一歩先へ:どの重みが変更されたか?
ランタイム可視性を補完するため、以下の 3 点を追求しています。
- モデルの重みが変更されたかどうか
- どのテンソルに影響を受けたか
- その変更を引き起こしたコード経路(コールスタック)は何か
研究の実行:イベントデータ構造
カーネル起動単独では「どのテンソルが書き換わったか」は不明ですが、フレームワークレベルのシグナルと Python コールスタックを結合することで特定可能です。
{ "timestamp": "2026-10-14T07:05:57.633569453Z", "metadata": { "event": "model_weight_mutation", "description": "モデルテンソルが非ローダーコールパスからインプレイスで書き込まれた", "tactic": "execution", "technique": "command_and_scripting_interpreter" }, "file": { "type": "tensor", "actions": ["tensor_write"], "stacks": [ { "frames": [ { "function": "MultiheadAttention.forward", "source": "torch/nn/modules/activation.py", "line": 1434 }, { "function": "Module._call_impl", "source": "torch/nn/modules/module.py", "line": 1793 }, { "function": "SpaceLM.forward", "source": "model.py", "line": 109 }, { "function": "_keys", "source": "calibration.py", "line": 40 }, // 【異常】編集コード { "function": "_calibrate", "source": "calibration.py", "line": 56 }, { "function": "<module>", "source": "rome_eval.py", "line": 11 } ] } ] }, "process": { "cmd": "python3.14", "args": "./.venv/bin/python space_chat.py", "pid": 112618, "uid": 0 }, "context": { "files": [ { "path": "examples/.../space_lm.pt", "actions": ["open", "read", "close"] }, { "path": ".../__pycache__/calibration.cpython-314.pyc", "actions": ["open", "read", "close"] } // 悪意あるバイナリ ], "network_flows": [ { "name": "huggingface.co", "status": "ended" }, { "name": "resolver", "status": "ongoing" } ] } }
イベントの読み取り:文脈における物語
イベント単体では「
calibration.py から書き込み」としか分かりませんが、**付与された文脈(Context)**によって以下が明らかになります。
- プロセスはチェックポイント(
)を読み込んだ。space_lm.pt - マルイアスなライブラリ(
)をインポートした。calibration.cpython-314.pyc - GPU デバイス(
)を開き、/dev/nvidia0
と通信した。huggingface.co
検出原理: 「ローダーパス(通常の読み込み)」以外のパスから重みが変化した際にはアラートが発火します。これは EDR が認証ライブラリからではなくシェルから認証情報ファイルを読み取るのをフラグするのと同じです。アクション自体は正常でも、コールスタックが真実を告げます。
結論:なぜ重要か
Stealthium のアプローチは以下の点で重要です。
- GPU 活動の有用なビュー:
およびCudaLibraryLoad
を記録し、Python 由来の場合はコールスタックを付与します。CudaKernelLaunches - ROME 攻撃の特定: この可視性により、疑わしいカーネル起動を直接それらを発したコード経路と結び付けることが可能です。
- 包括的な画像の構築: カーネル起動だけでは「どのテンソルが変更されたか」は不明ですが、フレームワークレベルの活動と Python コールスタックを結合することで、「何の目的で(推論か編集か)」重量が変更されたかを特定できます。
ROME の事例は、ランタイム GPU 可視性の価値と限界を検討する手段となります。当チームの取り組みは、AI ワークロードおよび LLM internals に対する可視性を増すことを目的としており、AI システムのセキュア化に寄与することを願っております。