セキュリティ

Claude Agent SDKの脆弱性CVE-2026-96620とは?0.2.121への更新とresume検証のコード

Claude Agent SDKの脆弱性CVE-2026-96620とは?0.2.121への更新とresume検証のコード

Python版のClaude Agent SDKに、セッション再開用の resume オプションを通じて任意のコマンドを実行できる脆弱性CVE-2026-96620が見つかりました。0.2.121より前の版が対象で、修正版は2026年7月17日にPyPIへ公開済みです。ただし危険なのは、Webアプリやチャットボットが利用者から受け取った文字列をそのまま resume に渡している場合に限られます。この記事では、仕組みと影響範囲、自社のコードが条件に当たるかの点検、更新コマンド、更新後も残しておきたいセッションIDの検証コードまでを順に示します。記載の基準は、2026年10月23日時点で確認できる公開情報です。

まとめ:CVE-2026-96620はSDKを0.2.121以上へ上げてresumeの入力元を確認

最初にやることは1つです。claude-agent-sdk を0.2.121以上へ更新してください。2026年10月22日時点の最新は0.2.172で、修正は3か月前に入っています。毎週のように新版が出るパッケージなので、ロックファイルで古い版に固定したまま運用しているケースが一番危険です。

次に、resume に渡している値の出どころを確かめます。社内のバッチが自分で保存したIDを使うだけなら、更新で対応は終わります。HTTPのリクエストやチャットの入力から来た値を渡しているなら、更新に加えてUUID形式の検証と、そのセッションの持ち主の確認を入れてください。

TypeScript版のSDKには、この件のアドバイザリは出ていません。Claude Code本体(CLI)を更新しても塞がらない点にも注意が要ります。

CVE-2026-96620の影響範囲とresume経由で任意コマンドが動く仕組み

Claude Agent SDKは、Claude Codeと同じエージェントの実行基盤を自社のプログラムから呼び出すためのライブラリです。基本の使い方や ClaudeAgentOptions の設定項目はClaude Agent SDKの使い方とインストール手順で解説しています。今回の欠陥は、そのPython版がCLIを子プロセスとして起動するときのコマンドライン組み立てにありました。

CVSS 4.0で9.2・AT:Pが付いた評価と影響を受ける版の範囲

AnthropicのアドバイザリGHSA-h4mw-j7qp-8mwmは2026年9月12日に公開され、深刻度はCritical、CVSS 4.0のスコアは9.2です。対象は claude-agent-sdk の0.2.121未満、つまり0.2.120以前のすべての版です。NVDのCVE-2026-96620には10月16日に登録され、10月23日時点ではNVD独自の評価は付いていません(Awaiting Analysis)。

ベクトルは AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H です。ネットワーク越しに認証なしで届き、成立すれば機密性・完全性・可用性のすべてに大きな影響が出ます。満点にならないのは、CVSS v4.0仕様でいう攻撃の前提条件(AT:P)があるためで、ここで該当すると読めるのは、「アプリが信頼できない値を resume に渡していること」です。v4.0のスコアの読み方はCVSS v4.0スコア9.2の読み解き方でも取り上げています。

弱点の分類はCWE-20(入力検証の不備)、CWE-78(OSコマンドインジェクション)、CWE-88(引数インジェクション)の3つが付いています。

–resumeの値がCLIのフラグとして読まれ–mcp-configが入り込む流れ

Python版のSDKは、同梱のClaude Code CLIを起動し、ClaudeAgentOptions の値をコマンドライン引数に変えて渡します。0.2.120までは、resume の値を --resume とは別の引数として並べていました。

CLI側の --resume は値を省略できるオプションです。そのため、値が - で始まっていると --resume の値として結び付かず、独立したフラグとして解釈されます。アドバイザリによれば、攻撃者はここに --mcp-config を差し込み、stdio型のMCPサーバーを定義できました。stdio型のMCPサーバーは、設定に書いたコマンドをCLIが子プロセスとして起動する仕組みです。結果として、CLIの起動時に任意のコマンドが走ります。

見落とせないのは、この実行がSDKの権限制御の外で起きる点です。allowed_tools や can_use_tool はエージェントのツール呼び出しを止める仕組みで、起動時に読み込まれるMCPサーバーのコマンドには効きません。MCPの基本はMCPの仕組みと構成要素を参照してください。

0.2.121の修正内容とTypeScript版・Claude Code本体の扱いの違い

修正はプルリクエスト #1123で入りました。--resume と --session-id を、--resume=<値> のように等号で結んだ1つの引数で渡す形に変えています。等号で結べば、値が - で始まっていてもフラグとは解釈されず、CLI側での扱いは、不正なセッションIDとしての拒否です。CHANGELOGの0.2.121にも同じ説明があり、同梱CLIは2.1.212に上がっています。

対象 この件の扱い
Python版SDK 0.2.120以前 影響あり
Python版SDK 0.2.121以降 修正済み
TypeScript版SDK アドバイザリなし
Claude Code CLIの更新 単独では塞がらない

原因はSDKが引数を並べる処理なので、直すべきはSDKの版です。TypeScript版リポジトリのSecurityタブには、10月23日時点で公開アドバイザリが1件もありません。

自社アプリが攻撃の条件に当てはまるかをコマンドとgrepで確かめる手順

点検は「版」と「入力元」の2つだけです。版が0.2.121以上なら入力元の点検は後回しにできますが、古い版が残る環境では両方を見ます。

pip showと__version__でclaude-agent-sdkの稼働版を確認

開発機ではなく、実際に動いている環境で確かめます。コンテナで動かしているなら、本番と同じイメージの中で次を実行してください。

# パッケージ管理上の版
pip show claude-agent-sdk

# 実行時に読み込まれている版(仮想環境の取り違えを防ぐ)
python -c "import claude_agent_sdk; print(claude_agent_sdk.__version__)"

2つの結果が食い違う場合、アプリが別の仮想環境を見ています。__version__ の値を正としてください。0.2.120以下なら次の章の更新に進みます。

resumeに渡す値の出どころをgrepで洗い出し入力元を分類する点検

次に、resume を設定している箇所をすべて探します。同じ形で修正された session_id も一緒に拾います。

# resume と session_id を設定している行を一覧にする
grep -rnE "resume\s*=|session_id\s*=" --include="*.py" ./src

見つかった箇所ごとに、値がどこから来たかを追います。危険度が高いのは、HTTPのパスやクエリ、リクエスト本文、Cookie、チャットの入力、キューに外部から積まれたメッセージから来る値です。逆に、直前の実行で ResultMessage から受け取り自分で保存したIDだけを使っているなら、攻撃者が値を差し込む経路はありません。

claude-agent-sdkを0.2.121以上へ更新しロックファイルで下限固定

SDKはPython 3.10以上で動き、CLIを同梱して配布されています。更新はパッケージ1つで完結し、CLIを別に入れ直す必要はありません。

pip・uv・Poetryで0.2.121以上を指定して更新するコマンド

使っているツールに合わせて、下限を付けて更新します。下限を書いておくと、ロックファイルを作り直したときに古い版へ戻る事故を防げます。

# pip
pip install -U "claude-agent-sdk>=0.2.121"

# uv(pyproject.toml と uv.lock を更新)
uv add "claude-agent-sdk>=0.2.121"

# Poetry(pyproject.toml と poetry.lock を更新)
poetry add "claude-agent-sdk>=0.2.121"

更新後は前の章の __version__ をもう一度確かめてください。0.2.121から最新の0.2.172までは50版ほどあり、その間もオプションの追加が続いています。動作確認の範囲が広がるのを避けたいなら、まず0.2.121へ上げて脆弱性だけを塞ぎ、最新版への追従は通常のリリースで行う、という2段構えも取れます。

cli_pathで別のCLIを指定している環境で見落としやすい更新箇所

SDKのREADMEのとおり、SDKは既定で同梱のCLIを使い、ClaudeAgentOptions(cli_path=...) を指定したときだけ別のCLIを起動します。社内で版をそろえるために cli_path を使っている環境では、「CLIは最新にしてあるので大丈夫」と判断しがちです。

しかし今回の修正は、SDKがCLIへ渡す引数の並べ方にあります。CLIがどれだけ新しくても、SDKが0.2.120以前なら引数は2つに分かれて渡ります。cli_path の有無にかかわらず、SDKの版を上げてください。

更新後も残しておきたいresumeのUUID検証とセッション所有者の確認

0.2.121で塞がったのは「フラグとして解釈される」経路だけです。利用者が任意のIDを resume に渡せる設計のままだと、他人のセッションを再開できてしまう問題が残ります。

UUID形式以外を拒否する検証関数をresumeの直前に置くコード例

Python版のリファレンスでは、session_id は「有効なUUIDでなければならない」とされています。resume に渡すIDも、結果メッセージから受け取ったUUIDのはずです。それ以外の形を通す理由はありません。

import uuid

def to_session_id(raw: str) -> str:
    """resume に渡す前に、正規形のUUIDだけを通す"""
    try:
        parsed = uuid.UUID(raw)
    except (ValueError, AttributeError, TypeError):
        raise ValueError("invalid session id")
    # 波括弧付き・urn:uuid: 付き・ハイフンなし・大文字は正規形と一致しないので拒否する
    if str(parsed) != raw:
        raise ValueError("invalid session id")
    return raw

assert to_session_id("5b3f2c1a-8d4e-4f6b-9a7c-2e1d0f9b8a6c")
for bad in ["--mcp-config", "-r", "{5b3f2c1a-8d4e-4f6b-9a7c-2e1d0f9b8a6c}"]:
    try:
        to_session_id(bad)
    except ValueError:
        print("rejected:", bad)

uuid.UUID は波括弧付きやハイフンなしの表記も受け付けるため、正規形の文字列と突き合わせて余計な形を落としています。- で始まる値はここで必ず止まります。

セッションIDを利用者に渡さずサーバー側の対応表で引くアプリ設計

公式のセッション解説によれば、セッションは ~/.claude/projects/ 配下にJSONLで保存され、CLI 2.1.223以降の resume は現在の作業ディレクトリの外まで探してIDを見つけます。同じサーバーで複数の利用者のセッションを扱うなら、形式が正しいIDでも別の利用者のものを再開できてしまいます。

from claude_agent_sdk import ClaudeAgentOptions

def build_resume_options(user_id: str, raw: str, sessions) -> ClaudeAgentOptions:
    session_id = to_session_id(raw)
    # sessions は自社DBの対応表(セッションIDと持ち主の利用者ID)を引く関数を持つ想定
    if sessions.owner_of(session_id) != user_id:
        raise PermissionError("session not found")
    return ClaudeAgentOptions(resume=session_id, allowed_tools=["Read", "Grep"])

さらに一歩進めるなら、画面やAPIにはアプリ独自の会話IDだけを見せ、SDKのセッションIDはサーバー側の対応表から引く形にします。利用者が触れる値が resume に直接届かなくなり、今回と同じ型の欠陥が別のオプションで見つかっても影響を受けにくくなります。外部からの入力をAPIでどう検証するかは、ハイフン始まりの入力を引数インジェクションとして扱う考え方とあわせて確認してください。

エージェントをWebアプリに組み込むときの権限と隔離を決める判断基準

今回の件は、SDKの権限設定だけではエージェントの実行環境を守りきれない例です。どこまで隔離するかを、組み込み方ごとに決めておきます。

利用者の入力が届くエージェントはコンテナ隔離を前提にする条件

不特定の利用者がチャットやAPIでエージェントを動かすサービスでは、SDKの更新と入力検証に加えて、エージェントの実行環境を隔離する構成を採ります。今回のように権限制御の外でコマンドが走っても、被害をそのコンテナから届く範囲で止められるからです。公式のセキュアデプロイ解説は、エージェントをコンテナに入れ、次のような制限を掛ける例を示しています。

# 公式解説の例から主な制限を抜粋(イメージ名やパスは環境に合わせる)
docker run \
  --cap-drop ALL \
  --security-opt no-new-privileges \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=100m \
  --network none \
  --user 1000:1000 \
  -v /path/to/code:/workspace:ro \
  agent-image

--network none で外へ出る経路を断ち、APIの認証情報はコンテナの外に置いたプロキシが付ける構成が推奨されています。今回の脆弱性で動くコマンドから手が届くのは、主に読み取り専用のコードと一時領域に限られます。

見送ってよいのは、社内の開発者だけが手元やCIで実行し、入力が自分たちのコードからしか来ない使い方です。この場合は更新と resume の入力元の点検で足ります。CIのランナーに本番の認証情報を置いているなら、そちらの整理を先に済ませてください。

AIエージェント組み込みの点検を自社で行うか外部に任せるかの境界

自社で完結できるのは、SDKの版を管理し、resume を含むオプションに外部入力が届く箇所を洗い出せる場合です。リポジトリが少なく、エージェントを呼ぶ箇所が数か所に収まっているなら、この記事の手順で足ります。コードからの機械的な洗い出しにはClaude Securityの脆弱性スキャンも使えます。

外部の目を入れたほうがよいのは、エージェントが社内システムの認証情報やファイルに触れる構成で、入力の経路が複数のサービスにまたがる場合です。プロンプトインジェクションやツール権限の設計まで含めて点検したいときは、AIセキュリティ対策の支援で、実行環境の分け方からまとめて相談いただけます。

よくある質問

CVE-2026-96620について、開発チームからよく出る疑問をまとめました。

TypeScript版のClaude Agent SDKもこの脆弱性の影響を受けますか?

10月23日時点で、TypeScript版のリポジトリに公開アドバイザリはありません。CVE-2026-96620の対象として示されているのは、PyPIの claude-agent-sdk だけです。ただ、利用者の入力をセッションIDとして渡す設計の危うさは言語を問いません。TypeScript版でも、resume に渡す値のUUID検証と持ち主の確認は同じように入れておくと安全です。

Claude Code本体を最新版にすればSDK側の更新は不要ですか?

不要にはなりません。問題はSDKがCLIを起動するときの引数の並べ方にあり、修正もSDKの0.2.121に入っています。cli_path で新しいCLIを指定していても、SDKが0.2.120以前なら値は別の引数として渡ります。SDKの版を上げてください。

CVE-2026-96620が悪用された事例は報告されていますか?

10月23日時点で、アドバイザリにもNVDにも悪用の報告はありません。CISAのKEVカタログ(10月21日版)にも掲載されていません。ただし修正の差分は公開されており、公開された情報から仕組みを読み解くことは容易です。外部入力を resume に渡しているアプリは、悪用報告を待たずに更新してください。

resumeに利用者の入力を渡していなければ更新を急がなくてよいですか?

攻撃の前提が成り立たないため、緊急度は下がります。社内バッチが自分で保存したIDだけを渡している場合などが該当します。とはいえ、将来の改修で外部入力が混ざる可能性は残るので、次の定例更新で0.2.121以上へ上げておくのが無難です。点検の結果に自信が持てないなら、先に更新してしまうほうが早く済みます。

session_idオプションにも同じ問題はありますか?

アドバイザリが名指ししているのは resume だけですが、0.2.121では session_id も等号で結んだ1つの引数として渡す形に変わりました。session_id はもともと有効なUUIDを指定する決まりなので、利用者の入力を渡しているなら resume と同じ検証関数を通してください。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.07.21 テックブログ Apache Tomcatの脆弱性一覧【2026年10月】最新版11.0.27・10.1.61・9.0.123とCVE-2026-59083ほかの影響確認・対応手順
  2. 2026.10.21 テックブログ NEC委託先の不正アクセスとは|顧客システム暗号化・情報漏えいの経緯と委託元が点検する正規アカウント
  3. 2026.10.21 テックブログ ふるさとチョイス不正アクセスで445万件流出:対象確認・パスワード変更と再開時期
  4. 2026.10.22 テックブログ Tomcatバージョン一覧とサポート期限【2026年10月】9.0系は2027年3月末で終了・9.1系と11.0系への移行判断
  5. 2024.07.05 コラム XAMPPの脆弱性とは?危険性とCVE-2024-4577への対策をわかりやすく解説【2026年10月】

RELATED POSTS 関連記事

目次