モデルを読み込むだけでコードが動くdiffusersのtrust_remote_codeすり抜け
対象の目安: 機械学習基盤や生成AIアプリを運用する実務担当者 / 実務

画像生成や動画生成の実装で広く使われているHugging Faceのdiffusersライブラリに、細工されたモデルリポジトリを読み込んだだけで任意のPythonコードが実行される脆弱性が3件公表されました。CVE-2026-44827、CVE-2026-44513、CVE-2026-45804の3件です。いずれも、外部のコードを走らせてよいかどうかを利用者に確認するためのtrust_remote_codeという仕組みをすり抜けます。既定値のままDiffusionPipeline.from_pretrained("組織名/モデル名")と書いただけで成立する経路が含まれます。
モデルの配布は、重みという巨大な数値の塊を配るだけの行為に見えます。ところがdiffusersには、リポジトリ側にPythonファイルを置いておくと、それを読み込み側で実行してパイプラインの一部として使う仕組みがあります。カスタムパイプラインとカスタムコンポーネントと呼ばれる機能です。この機能があるため、モデルリポジトリの実体は「データ」ではなく「データと実行コードの混在物」です。信頼境界はここに引かれます。
trust_remote_codeは、その境界を利用者の明示的な同意で越えさせるための引数です。既定値はFalseで、リポジトリに実行対象のコードが含まれていればエラーで止まる想定でした。今回公表された3件は、この停止機構が働かない道筋が複数残っていた、という内容です。
この記事は、機械学習基盤や生成AIアプリを運用する実務担当者に向けて、GitHub Security Advisoryの3本、NVDの各エントリ、修正が入ったPull Request #13448とバグ報告のIssue #13446、リリースv0.38.0、Hugging Faceの公式ドキュメント、報告者側の技術ブログにもとづき、事実関係と対応を整理します。攻撃コードは扱いません。記述は執筆時点(2026年8月4日)に一次情報から確認できた範囲に限ります。
3件のCVEと修正版の対応関係
まず数値と版の関係を確定させます。3件はすべてhuggingface/diffusersリポジトリのGitHub Security Advisoryとして公開され、CVEはGitHub, Inc.がCNAとして採番しています。
| CVE | GHSA | 内容 | CVSS 3.1 | CWE | GitHub Advisory Database公開日 |
|---|---|---|---|---|---|
| CVE-2026-44827 | GHSA-j7w6-vpvq-j3gm | None.pyによるtrust_remote_codeバイパス | 8.8 High (AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H) | CWE-94 | 2026-05-07 |
| CVE-2026-44513 | GHSA-98h9-4798-4q5v | custom_pipelineとローカルのカスタムコンポーネント経由のバイパス | 8.8 High (AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H) | CWE-94 | 2026-05-07 |
| CVE-2026-45804 | GHSA-7wx4-6vff-v64p | 設定取得とリポジトリ取得の間の競合状態によるバイパス | 7.5 High (AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H) | CWE-367 | 2026-05-20 |
影響範囲はGitHub Advisory DatabaseとOSVのいずれも「diffusers(PyPI) 0.38.0未満」で、最初の修正版は0.38.0です。v0.38.0のリリースはGitHub上で2026年5月1日(UTC)、PyPIへの公開も同日です。執筆時点のPyPIの最新版は2026年7月3日公開の0.39.0です。
表の日付はGitHub Advisory Databaseへの掲載日です。日付の起点は複数あるため、資料を突き合わせるときは区別が要ります。huggingface/diffusersリポジトリのSecurity Advisoryページ上に表示される公開日は、CVE-2026-44827とCVE-2026-44513がいずれも2026年5月1日、CVE-2026-45804が2026年5月20日で、前2件は数日ずれます。各Advisoryページの見出し部分と、GitHubのAdvisory API(https://api.github.com/advisories/GHSA-j7w6-vpvq-j3gmなど)のpublished_atを比べると差分が確認できます。
NVDでの公開日はCVE-2026-44827とCVE-2026-44513が2026年5月14日、CVE-2026-45804が2026年7月15日です。3件ともCVSS 3.1の数値はCNAであるGitHubの提供値で、NVDが独自に付けるCVSS 4.0の評価は執筆時点で掲載されていません。
CVSSベクトルのうち、UI:R(利用者の関与が必要)が付いている点は読み方に注意が要ります。ここでの関与は「怪しい操作をわざわざする」という意味ではなく、「対象のモデルリポジトリを読み込む処理を実行する」ことを指します。既定の引数だけで成立する経路がある以上、実務上の障壁としては低いものです。
深刻度スコアの各項目の意味と、環境条件を織り込んだ読み方は次の記事で整理しています。
あわせて読みたい
脆弱性対応の優先順位付け。CVSSだけに頼らないEPSSとCISA KEVの使い方
trust_remote_codeが守るはずだった境界
diffusersのカスタムパイプラインは、from_pretrained()にcustom_pipelineという引数を渡すと有効になります。Hub上のリポジトリを指定する場合、そのリポジトリにはpipeline.pyという名前のファイルが必要で、読み込み側はこれをimportしてパイプラインクラスとして使います。GitHub上のコミュニティパイプライン集を名前で指定する使い方もあります。
カスタムコンポーネントも同じ考え方です。モデルリポジトリのmodel_index.jsonで、UNetやスケジューラの実装として標準クラスの代わりに自前のPythonモジュールを指定しておくと、読み込み側でそのファイルが実行されます。公式ドキュメントが作例として案内するリポジトリ(sayakpaul/show-1-base-with-code)のmodel_index.jsonでは、unetの項目が["showone_unet_3d_condition", "ShowOneUNet3DConditionModel"]という2要素の配列になっており、モジュール名とクラス名が並びます。パイプラインのクラスそのものを差し替える場合は、同じ書き方を_class_nameに対して行います。読み込み側は配列の1つ目の要素に.pyを付けたファイルを探して読み込みます。
公式ドキュメントは、Hubのパイプラインについて「Hugging Face Hubはファイルをスキャンしているが、それでもHubのパイプラインコードを自分で確認して安全であることを確かめるべきである」と警告しています。さらにtrust_remote_code=Trueを使う場合の追加の予防策として、コミットハッシュをrevision引数へ渡すことを強く推奨しています。悪意あるコードに差し替えられていないことを確かめるため、という理由が明記されています。
つまり設計上の想定は、「コードが含まれるなら止める。利用者が中身を読んで納得したときだけtrust_remote_code=Trueで通す」という一点の関門でした。今回の3件は、この関門を通らずに済む道が複数あった、という話です。
ここで区別しておきたいのが、重みファイル自体の危険性との違いです。PyTorchの重みで長く使われてきたpickle形式は、読み込むだけで任意のコードが動く形式で、safetensorsへの移行はその問題への答えでした。安全な形式の重みを使っていても、今回の経路は影響を受けます。実行されるのはリポジトリに同居する.pyファイルであって、重みの中身ではないためです。safetensorsを使っているから安心という判断は当てはまりません。
モデルやAI基盤に固有のリスクの見取り図は次の記事で扱っています。
あわせて読みたい
プロンプトインジェクションとは。AIエージェント時代の新しい攻撃と防御
ゲートの置き場所が招いたすり抜け
CVE-2026-44513は3つの変種をまとめたものです。報告のきっかけになったIssue #13446は2026年4月12日にVancir氏が提出しました。指摘の内容は、trust_remote_codeの確認が主モデルリポジトリに対してのみ行われ、custom_pipelineで指定した外部リポジトリに対しては行われていない、というものです。
0.37.1のコードを見ると構造がはっきりします。DiffusionPipeline.download()の中で、判定は次の1行に依存していました。
load_pipe_from_hub = custom_pipeline is not None and f"{custom_pipeline}.py" in filenames
filenamesは主モデルリポジトリのファイル一覧です。custom_pipelineに別のリポジトリIDを渡した場合、そのリポジトリにあるpipeline.pyは主リポジトリの一覧には現れません。条件は偽になり、trust_remote_codeの確認は行われないまま、あとの処理が外部リポジトリのpipeline.pyを取得して実行しました。
2つ目の変種は、主モデルをローカルディレクトリで指定しつつ、custom_pipelineにはHub上の別リポジトリを渡した場合です。snapshot_download()で先にダウンロードしておいたパスを渡すと、download()のHub向けの分岐そのものを通らないため、確認は一度も行われないまま外部リポジトリのコードが実行されました。3つ目の変種は、ローカルのスナップショットにカスタムコンポーネントのPythonファイルが含まれている場合です。こちらも同じ理由で確認されないまま読み込まれました。
依存パッケージ経由でコードが持ち込まれる構図そのものは、npmエコシステムで繰り返し観測されてきたものと同じです。
あわせて読みたい
自己増殖するnpmサプライチェーンワーム。Shai-Huludとその亜種が広がる仕組みと防御
既定値のNoneがファイル名になるCVE-2026-44827
3件のうち、既定の呼び出しだけで成立する点で性質が異なるのがCVE-2026-44827です。Advisoryは発生箇所としてpipeline_loading_utils.pyの976行目を挙げています。0.37.1のソースを確認すると、その前後は次のとおりです。
def _resolve_custom_pipeline_and_cls(folder, config, custom_pipeline):
custom_class_name = None
if os.path.isfile(os.path.join(folder, f"{custom_pipeline}.py")):
custom_pipelineを指定しなければ値はNoneです。f文字列にNoneを埋めると文字列"None"になるため、この条件は「ダウンロード済みフォルダにNone.pyというファイルがあるか」を確かめるものに変わります。ファイル名の組み立てにPythonのオブジェクトがそのまま流し込まれた結果です。
ダウンロード側にも同じ書き方が残っていました。0.37.1のdownload()は、取得対象のパターンにf"{custom_pipeline}.py"をリポジトリのファイル一覧に含まれる場合のみ追加します。custom_pipelineがNoneのときこの式は"None.py"になるため、攻撃者のリポジトリにNone.pyが置いてあれば取得対象に入り、ローカルへ落ちます。一方で先ほどの関門はcustom_pipeline is not Noneという条件のせいで偽のままです。ファイルは降りてくるのに、確認だけが飛ばされる状態でした。
model_index.json側では通常のクラス名を書いたままにできるため、リポジトリの見た目は普通のモデルです。読み込み側のコードにもcustom_pipelineやtrust_remote_codeという文字は現れません。報告者は、引数なしのfrom_pretrained('repo')だけで成立する静かなコード実行だと表現しています。
ファイル名やクラス名の解決に外部が影響できる形は、Pythonのpickleを含む逆シリアル化の問題と同じ構造を持ちます。
あわせて読みたい
安全でないデシリアライゼーションの対策。信頼できないデータの復元が任意コード実行につながる仕組み
設定取得とリポジトリ取得の間に生じるCVE-2026-45804
CVE-2026-45804は競合状態です。diffusersは、モデルを取得するときにHubへ2回別々のHTTPリクエストを出します。1回目はhf_hub_downloadでmodel_index.jsonだけを取り、この内容に対してtrust_remote_codeの判定を行います。2回目はsnapshot_downloadでリポジトリのファイル群を取得します。
revisionを指定しない場合、2回のリクエストはそれぞれ呼び出し時点の既定ブランチのHEADを解決します。2つの解決の間に原子性の保証はありません。攻撃者が2回のリクエストの間にリポジトリを更新すれば、判定に使われた設定と実際にダウンロードされる中身が食い違います。
Advisoryは成立条件も明記しています。キャッシュ済みの内容では成立しないため初回のダウンロードが必要であること、revisionにコミットハッシュを固定していると成立しないこと、そして時間差が短いため利用の多いリポジトリを狙って確率的に成功させる形になることです。窓の長さは資料によって数値が異なり、Advisory本文は約0.5秒、報告者側のブログは約0.3秒と記しています。いずれも局所環境での実測値として示されたものです。
条件が重なる分だけCVSSの攻撃条件はAC:H(高)と評価され、値も7.5にとどまりました。ただし緩和策としては強い含意があります。revisionにコミットハッシュを固定すればこの経路は成立しません。時間差そのものを消せる操作だからです。
0.38.0の修正が変えたもの
修正はhlky氏によるPull Request #13448「Improve trust_remote_code」です。2026年4月23日にマージされ、7ファイルで178行の追加と27行の削除が入りました。マージコミットはa37f6f8394ac2a7ee8360c3abea811efe54512b1です。
方針は関門の移設です。取得処理のdownload()にあった判定を取り除き、動的モジュールを読み込む唯一の通り道であるget_cached_module_fileへ集約しました。0.38.0のコードでは、ローカルディレクトリの.pyを読む場合とHubのリポジトリから読む場合に、この関数の中でtrust_remote_codeが確認されます。diffusers公式のコミュニティパイプラインミラーから読む経路については、供給元が公式のデータセットであるため信頼できる扱いとされており、trust_remote_codeの確認は入りません。_get_pipeline_classや_get_custom_pipeline_classにもtrust_remote_code引数が追加され、値が末端まで渡るようになりました。
注意したい点として、None.pyを組み立てる文字列補間そのものは0.38.0でも残っています。0.38.0の_resolve_custom_pipeline_and_clsは0.37.1と同じ実装です。つまりファイル名の解決結果としては同じNone.pyにたどり着きますが、その先の読み込み地点でtrust_remote_codeが確認されるため、既定のままでは例外で止まります。個々の入口を塞ぐのではなく、実行の直前に一つの関門を置く形です。
修正版には全面停止の手段も用意されています。DIFFUSERS_DISABLE_REMOTE_CODE環境変数に1やtrueといった値を設定すると、trust_remote_code=Trueが渡されても無視され、リモートコードの読み込みは常にエラーになります。真として扱われる値はutils/import_utils.pyのENV_VARS_TRUE_VALUESで定義されており、大文字小文字は区別されません。この定数自体は0.37.1にも存在しますが、0.37.1で参照しているのはresolve_trust_remote_codeだけで、その呼び出し元はAutoModelとモジュラーパイプラインの2系統に限られます。DiffusionPipeline.from_pretrainedの経路では参照されないため、0.37.1でこの環境変数を設定しても今回の3件は止まりません。判定をget_cached_module_fileへ移した0.38.0で初めて、モジュール読み込みの通り道そのもので効くようになりました。
データベース側の食い違いと検知の落とし穴
依存関係スキャナで拾えるかどうかは、脆弱性データベース側の状態に左右されます。ここに執筆時点で確認できる食い違いがあります。
GitHub Advisory DatabaseのAPIでGHSA-j7w6-vpvq-j3gm(CVE-2026-44827)を取得すると、withdrawn_atに2026年5月7日05時25分32秒(UTC)が設定されています。公開されたのが同日02時24分22秒(UTC)ですから、公開から約3時間後に取り下げられた形です。同じ状態はOSVのエントリにも反映されており、要約文もCVE-2026-44513側の文言に置き換わっています。取り下げの理由そのものについて公式の説明は執筆時点で確認できませんでした。ただしAdvisory本文の末尾には、専用のCVEを割り当てるべき理由を述べた節が残っています。CVE-2026-44513は利用者が渡すcustom_pipeline引数か設定側の宣言を必要とする関門の置き場所の欠陥であるのに対し、こちらは既定値Noneがファイル名へ補間される文字列組み立ての欠陥であり、根本原因も発火条件も異なる、という主張です。重複として扱うかどうかのやり取りがあったことがうかがえます。
一方でNVDのCVE-2026-44827は取り下げ状態ではなく、CVSS 8.8とCWE-94を掲載したまま公開されています。参照するデータ源によってこのCVEが見えたり見えなかったりする、ということです。実務では、単一のフィードだけで「該当なし」と結論づけないほうが安全です。幸い3件とも影響範囲は同じ0.38.0未満で、修正版も同じ0.38.0ですから、版で判断すれば取りこぼしません。
CISAのKEVカタログは2026年8月6日時点の最新版(2026.08.05、収録1661件)を確認しましたが、3件とも収録されていません。Hugging Faceやdiffusersを対象とする項目自体がありません。実環境での悪用が確認されたという公式の記載も見つかりませんでした。ただしNVDに併記されるCISA-ADPのSSVC評価を見ると、CVE-2026-44827とCVE-2026-45804はexploitationがpoc、CVE-2026-44513はnoneです。SSVCのpocは、実際の悪用が観測された状態を示すactiveとは別の区分です。KEV未収録を悪用手段が存在しないことと読み替えないほうが安全です。
依存パッケージの棚卸しとスキャナの運用は次の記事で整理しています。
あわせて読みたい
依存ライブラリ管理とSCA。SBOMで攻撃面を把握する
影響範囲の確認手順
自組織が影響を受けるかどうかは、インストールされているdiffusersの版で決まります。0.38.0未満であれば3件とも該当します。確認は実行環境ごとに行います。開発者の手元、CIのコンテナ、推論サーバー、Jupyter基盤、それぞれで版が違うことは珍しくありません。
diffusersの影響範囲を確認する手順
- 1
各実行環境でpip show diffusersを実行し、Versionの値を記録する。0.38.0未満なら該当する
- 2
requirements.txtやpyproject.tomlの記述だけで判断せず、実際に解決された版をpip freezeやuv pip listで確認する。上限を固定していない書き方では古い版が残っていることがある
- 3
requirements.lockやpoetry.lock、uv.lockなどのロックファイルでdiffusersの固定版を確認し、リポジトリ間で食い違いがないかを見る
- 4
コンテナイメージについては、稼働中のイメージに対してpip showを実行して確認する。ベースイメージが更新されていない環境が残りやすい
- 5
diffusersを直接書いていなくても、他のライブラリの依存として入っていることがある。pip show diffusersのRequired-by欄で参照元を確認する
- 6
SCAツールを使う場合は、GitHub Advisory Database系とNVD系の両方の結果を突き合わせる。CVE-2026-44827はデータベース側で取り下げ状態のため片方だけでは出ないことがある
- 7
モデルの読み込み経路を洗い出し、from_pretrainedの呼び出し箇所とrevisionの指定有無を一覧にする
- 8
利用しているモデルリポジトリの提供元を一覧化し、自組織以外が管理するものを区別する
最後の2つは更新後も残る作業です。ライブラリを直しても、実行するコードの出どころを把握していなければ、次に似た欠陥が出たときの影響評価がやり直しになります。
0.38.0への更新と当面の緩和策
対応の基本は0.38.0以上への更新です。執筆時点の最新版は0.39.0です。報告者側のブログも、0.38.0以降への即時の更新を第一の推奨として挙げています。
更新の際は互換性の確認が必要です。0.37系から0.38系へ上がるとパイプラインの追加やAPIの変更が入ります。リリースノートに変更点が列挙されているため、自組織で使っているパイプラインが該当するかを先に確認します。v0.38.0のリリースノートには、torchaoの量子化設定で文字列指定を廃止する変更(PR #13291)や、torchaoの最低バージョンを0.15.0へ引き上げる変更(PR #13355)も含まれます。影響の出方は利用しているパイプラインや量子化の構成、周辺ライブラリの版によって変わるため、検証環境で実際のモデルを読み込む回帰確認を挟んでから本番へ適用します。
すぐに更新できない場合に効く緩和は、脆弱性ごとに性質が異なります。前提として、GHSA-98h9-4798-4q5vは回避策の項で、これらは緩和策であって修正ではなく、完全な解消は0.38.0への更新だけだと明記しています。
| 緩和策 | 効く範囲 | 補足 |
|---|---|---|
| DIFFUSERS_DISABLE_REMOTE_CODE環境変数を有効にする | 0.38.0以降でのリモートコード読み込み全般 | 0.38.0以降でのみ有効です。0.37.1にも同名の定数はありますが、DiffusionPipeline.from_pretrainedの経路からは参照されないため、今回の3件に対する緩和にはなりません。更新前の緩和は社内ミラーと取り込み時の.py検査、revisionの固定に寄せます |
| revisionにコミットハッシュを固定する | CVE-2026-45804の競合状態 | 2回の取得が同じコミットを指すため時間差が消えます。公式ドキュメントもtrust_remote_code=True利用時の追加の予防策として推奨しています |
| モデルを事前に取得して社内ミラーへ置き、local_files_onlyで読む | Hubへの直接アクセス全般 | 取り込み時点で検査でき、取り込み後の書き換えの影響も受けません。ローカルに置いたPythonファイルを読み込む経路は0.38.0未満では止まらないため、取り込み時の検査が前提です |
| 推論プロセスの外向き通信を絞る | 実行後の外部への持ち出し | コード実行そのものは防げませんが、資格情報の送出や追加ペイロードの取得を難しくします |
| 推論プロセスを最小権限で動かす | 実行後の被害範囲 | クラウドのインスタンスロールやKubernetesのサービスアカウント権限を見直します |
環境変数による全面停止が止めるのは、カスタムパイプラインだけではありません。0.38.0のget_cached_module_fileは、この環境変数が真なら関数の入口で例外を送出します。カスタムコンポーネントの読み込みも、ローカルディレクトリに置いた.pyを読む経路も、同じ関門を通るため一律に止まります。副作用がないと言えるのは、カスタムパイプラインとカスタムコンポーネントのどちらも使っていない環境です。自組織で使うモデルが標準のクラスだけで動くかどうかは、検証環境で環境変数を設定したうえで実際にfrom_pretrained()を通し、例外が出ないことを確かめてから常設に移します。コンテナで動かしているなら、イメージのビルド時点で環境変数を焼き込んでおくと、実行時の設定漏れを避けられます。
revisionのコミットハッシュ固定は、競合状態を消すだけでなく再現性の面でも効きます。ブランチ名を指定した読み込みは、上流のリポジトリが更新されるたびに中身が変わります。同じコードが昨日と今日で違うファイルを読む状態は、障害の切り分けも侵害の調査も難しくします。運用中のモデルは、ハッシュで固定して変更を意図的な作業として扱うほうが扱いやすくなります。
社内ミラーを置く方式は手間が増えますが、得られるものが多い緩和です。取り込みの窓口が1本になるため、リポジトリ内の.pyファイルの有無を機械的に確認する工程を挟めます。加えて、local_files_only=Trueで読むようにすれば、推論ホストからHubへの通信そのものを止められます。読み込み時に外部へ出ていく必要がなくなるため、ネットワーク側の制限も設計しやすくなります。
ただし、ローカルに置いたこと自体は防御になりません。CVE-2026-44513の3つ目の変種は、ローカルのスナップショットに含まれるカスタムコンポーネントのPythonファイルが読み込まれる経路です。0.38.0未満のdiffusersでは、ミラー経由で配置したファイルであっても同じように実行されます。GHSA-98h9-4798-4q5vも回避策として、ローカルスナップショットに対してfrom_pretrainedを呼ぶ前に、想定外の.pyファイルがないかをコンポーネントのサブディレクトリとルートの双方で確認するよう挙げています。有無を数えるだけでは足りず、見つかった場合は内容のレビューと承認を経てから配置する、という運用にして初めて意味を持ちます。
モデル配布をサプライチェーンとして扱う
今回の3件が示しているのは、モデルリポジトリが実行コードの配布経路でもある、という事実です。Hugging Face Hubには検査の仕組みがありますが、それが何をどこまで見ているかを把握したうえで運用を組む必要があります。
ClamAVは、ハッシュ、本文のパターン、YARAルール、バイトコード署名といった複数の形式の定義にもとづいて既知の脅威を判定する仕組みです。対応する定義の種類は公式ドキュメントのSignaturesの章に一覧があります。Hugging Faceがどの定義群をどう運用しているかは公開資料からは確認できませんでしたが、少なくとも、攻撃者がその場で書いた数行のPythonファイルまで確実に検出できるという説明はありません。Hugging Face自身も、pickleスキャンのページで「100パーセント確実なものではない」と明記しています。pickleのimportスキャンは重みファイルの中身に対する検査であって、None.pyやpipeline.pyのようなテキストのPythonファイルを審査するものではありません。プラットフォーム側の検査は、リポジトリの中身が安全であることの保証ではない、という前提で組み立てます。
常設の運用として整えたい項目を並べます。
- 各実行環境のdiffusersが0.38.0以上である
- 本番で読み込むモデルリポジトリが一覧化され、提供元と用途が記録されている
- from_pretrainedの呼び出しでrevisionにコミットハッシュを固定している
- カスタムパイプラインを使わない環境でDIFFUSERS_DISABLE_REMOTE_CODEを有効にしている
- trust_remote_code=Trueを使う箇所が限定され、対象コードのレビュー記録が残っている
- 外部モデルを社内ミラーへ取り込む工程があり、取り込み時にリポジトリ内のPythonファイルの有無を確認し、見つかった場合は内容のレビューと承認を経ている
- 推論プロセスの外向き通信が必要な宛先に限定されている
- 推論プロセスが持つ資格情報が最小権限で、有効期限のある形式になっている
- SBOMにdiffusersを含むPythonの依存が記録され、SCAの結果を定期的に確認している
- SCAの参照元がGitHub Advisory Database系とNVD系の双方をカバーしている
- モデルの読み込みが起きたホストのプロセス生成と外向き通信のログを取得している
モデルの取り込みを審査する工程を持つと、この種の欠陥が次に出たときに、影響範囲の特定と更新対象の優先順位付けを短い時間で進められます。逆に、開発者が思い思いにHubのIDを書ける状態のままだと、どのリポジトリを読み込んでいるかの把握から始めることになります。
外部のコードやツールを実行時に読み込む設計の危うさは、AI基盤の別の領域でも同じ形で現れています。
あわせて読みたい
MCPサーバーのセキュリティ。AIエージェントとツール接続の信頼境界
検証を行う場合の注意
再現確認を行う場合は、自組織が管理する隔離環境に限って実施します。第三者が公開しているリポジトリに対して攻撃的な検査を行うことや、許可のない環境でコードを実行させることは、関連法令や利用規約に抵触するおそれがあります。
注意
Issue #13446やAdvisoryには再現用のコード片が含まれますが、実行すると外部リポジトリのPythonコードが手元で動きます。本番の資格情報が読める環境や、社内ネットワークへ到達できる端末では実行しないでください。確認が必要な場合は、外部通信を遮断した使い捨てのコンテナで行います。
対応の記録として残しておきたいのは、更新前に該当版を使っていた期間と、その期間に読み込んだモデルリポジトリの一覧です。実環境での悪用が確認されたという公式の記載は執筆時点で見つかりませんでしたが、外部提供のモデルを既定の引数で読み込んでいた環境があったなら、プロセス生成と外向き通信のログを遡って確認する価値はあります。
まとめ
diffusersの3件は、モデルリポジトリが重みだけでなく実行コードの配布経路でもあるという前提を、実装の細部で崩していた例です。trust_remote_codeという関門は用意されていたものの、その置き場所が取得処理の中だったため、取得処理を通らない経路、ファイル名の解決が既定値で変わる経路、判定と取得の間に時間差が生じる経路の3方向から素通りできました。0.38.0の修正は、関門を実行の直前に一つだけ置くという方針の変更です。
実務としてやることは3段階です。まず各実行環境のdiffusersを0.38.0以上へ更新します。次に、revisionのコミットハッシュ固定とDIFFUSERS_DISABLE_REMOTE_CODEの設定という、次の欠陥にも効く設定を常設にします。そして、読み込むモデルリポジトリを一覧化し、外部提供のものを取り込み工程の対象にします。ライブラリの更新は都度の作業ですが、あとの2つは仕組みとして残ります。
数値と版の関係を最後に整理します。影響はdiffusers 0.38.0未満、修正は0.38.0、執筆時点の最新は0.39.0です。CVE-2026-44827とCVE-2026-44513がCVSS 8.8、CVE-2026-45804が7.5です。CISAのKEVカタログには3件とも収録がありません。CVE-2026-44827はGitHub Advisory DatabaseとOSVで取り下げ状態のため、スキャナの結果が参照元によって変わる点だけ覚えておくと確認の抜けを防げます。
出典・参考
- GitHub Security Advisory GHSA-j7w6-vpvq-j3gm: None.py Trust Remote Code Bypass (CVE-2026-44827)
- GitHub Security Advisory GHSA-98h9-4798-4q5v: trust_remote_code bypass via custom_pipeline and local custom components (CVE-2026-44513)
- GitHub Security Advisory GHSA-7wx4-6vff-v64p: TOCTOU Trust Remote Code Bypass (CVE-2026-45804)
- NVD: CVE-2026-44827 Detail
- NVD: CVE-2026-44513 Detail
- NVD: CVE-2026-45804 Detail
- huggingface/diffusers Issue #13446: Insufficient trust check for custom_pipeline parameter of DiffusionPipeline.from_pretrained method
- huggingface/diffusers Pull Request #13448: Improve trust_remote_code
- huggingface/diffusers Release v0.38.0
- Hugging Face Diffusers Docs: Community pipelines and components
- Hugging Face: sayakpaul/show-1-base-with-codeのmodel_index.json
- Hugging Face Diffusers Docs: Pipelines (DiffusionPipeline API)
- huggingface/diffusers v0.38.0: src/diffusers/utils/dynamic_modules_utils.py
- huggingface/diffusers v0.37.1: src/diffusers/pipelines/pipeline_loading_utils.py
- Hugging Face Hub Docs: Malware Scanning
- ClamAV Documentation: Signatures
- Hugging Face Hub Docs: Pickle Scanning
- OSV: GHSA-j7w6-vpvq-j3gm
- OWASP Gen AI Security Project: LLM03:2025 Supply Chain
- CISA Known Exploited Vulnerabilities Catalog
- Zafran Labs: FaceHugger: Vulnerabilities in Hugging Face Diffusers Open Door to Supply Chain Attacks on Enterprise AI
- IPA: AIセキュリティ
- PyPI: diffusers
関連する記事
プロンプトインジェクションとは。AIエージェント時代の新しい攻撃と防御
LLMアプリやAIエージェント、コーディング支援を狙うプロンプトインジェクションの仕組みを、直接型と間接型に分けて解説。実例とOWASP/IPAの最新動向をもとに、権限分離や人間の承認といった実務の防御設計までを整理します。
MCPサーバーのセキュリティ。AIエージェントとツール接続の信頼境界
AIエージェントを外部ツールにつなぐMCPサーバーの攻撃面を、ツールポイズニングや間接プロンプトインジェクション、過剰な権限とトークンの扱い、信頼できないサーバーとrug pullに整理し、利用者と開発者と組織の防御を公式仕様をもとに解説します。
自己増殖するnpmサプライチェーンワーム。Shai-Huludとその亜種が広がる仕組みと防御
盗んだnpmトークンで自分を別パッケージへ再公開し、自動で広がるnpmワームの仕組みを、Shai-Huludとその亜種の事例から解説します。install時にコードが走る経路と、開発者と組織それぞれの防御策を整理します。


