flawopen.com/Teardowns/cve-2026-71433-langgraph-store-namespace-boundary
LangGraph CVE-2026-71433:namespace越境
LangGraphのPostgres/SQLiteストアで、範囲指定した読み取りがnamespace境界を越え、隣接テナントのデータを返す可能性がありました。両パッケージを3.1.1へ更新してください。
CVSS ベクトル
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:N図書館員に「チーム」で始まる名前のフォルダーを探してもらう場面を考えてください。目録が文字列の先頭だけを検索すると、「チーム2」まで返ることがあります。LangGraphはnamespaceのラベルをドットで連結していましたが、前方一致でそのドットを境界として必須にしていませんでした。修正ではnamespaceそのものとの一致、または実際の次セグメントを要求するため、別テナントのフォルダーが混ざらなくなります。
主要な概念と専門用語
Namespace- LangGraph Storeが項目をまとめるために使うラベルのタプルです。アプリケーションはユーザーやテナントの境界として使うことがあります。
Prefix scope- 1つのnamespaceとその子孫を読む指定です。正しい一致ではセグメント境界を守ります。
fooはfoo.childを含みますが、兄弟のfoobarは含みません。 SQL `LIKE` pattern%は任意の文字列、_は1文字に一致するテキストパターンです。namespaceラベルを文字どおり扱うには、これらの文字をエスケープします。CWE-863- 不適切な認可:呼び出し元が読み取りを許可されていないnamespaceのレコードをStoreが返しました。
フレームワーク対応
- このガイドで説明する弱点の CWE 参照: CWE-863
根本原因の分析 (Root Cause)
3.1.1より前のPostgres/SQLite checkpoint storeは、namespaceのタプルをドット区切りの文字列に変換し、LIKE '<namespace>%'で検索範囲を限定していました。LIKEはnamespaceの区切りを認識しないため、fooの検索が兄弟namespaceのfoobarにも一致することがありました。許可されている%と_のラベルもワイルドカードとして働く可能性がありました。list_namespacesにもprefixとsuffixに関する同様の誤りがありました。通常の範囲指定読み取りで発生し、細工した入力は不要です。影響するのはPostgres/SQLite Storeのsearchおよびnamespace一覧取得の読み取り経路で、アプリがnamespaceをテナント分離に使う場合です。get、put、deleteは完全一致を使うため影響せず、InMemoryStoreも要素単位で比較するため影響しません。修正では完全一致または子孫セグメントの前にドットを要求し、LIKEメタ文字をエスケープし、namespace一覧にはセグメント認識パターンを使います。SQLiteでは検索時にLIKEのASCII大文字小文字を区別しない挙動も回避します。勧告に実環境での悪用報告はありません。対象パッケージは3.1.1で修正済みです。
CVE-2026-71433 の構成別到達性マトリクス
| 構成と namespace の形式 | 確認されている動作 | トリアージ対応 |
|---|---|---|
| PostgresStore / AsyncPostgresStore または SqliteStore / AsyncSqliteStore が 3.1.1 未満で、tenant 分離を namespace に依存している。 | 範囲指定された search または list_namespaces は、ラベルがテキスト上の接頭辞を共有する場合(foo / foobar、1 / 12)、または % / _ を含む場合に隣接 namespace まで一致することがあります。SQLite の検索では ASCII の大文字小文字だけが異なる名前も同一視されました。 | 該当する checkpoint パッケージを 3.1.1 以降に更新します。本番 backend で隣接接頭辞、ワイルドカード、suffix、一文字だけ大文字小文字が異なるケースをテストします。 |
| 3.1.1 未満の SQLite Store で、namespace ラベルが ASCII の大文字小文字だけ異なる。 | 脆弱な子孫検索は大文字小文字を区別しない LIKE を使っていましたが、完全一致の操作は区別していました。 | 更新し、ラベルがそのように異なる可能性があれば大文字小文字の回帰テストを追加します。 |
% と _ を含まない固定長 UUID ラベル。 | アドバイザリによると、この形式は影響を受けません。固定長ラベル同士が接頭辞になることはありません。 | すべての namespace セグメントがこの条件を満たすか確認します。長さが変わる、またはワイルドカードを含む場合は影響ありとして扱います。 |
| InMemoryStore。 | 影響を受けません。namespace の各要素を個別に比較します。 | この CVE による更新は不要ですが、アプリケーション境界で tenant の所有権を確認してください。 |
| LangSmith のホステッド環境。 | 既定の LANGGRAPH_STORE_BACKEND=python は AsyncPostgresStore を使うため、影響バージョンのパッケージでは対象です。別の grpc backend には同等の修正が入りました。 | 設定された backend と実際のバージョンを確認します。製品名だけで判断せず、ホステッド環境の更新状況を確かめてください。 |
ステップ・バイ・ステップの攻撃フロー
ストアの種類とラベルを確認
3.1.1未満のlanggraph-checkpoint-postgresまたはlanggraph-checkpoint-sqliteを使い、namespaceでユーザーやテナントを分離している必要があります。共通のprefixや%、_を含むラベルがあると境界の影響を受けます。
通常の範囲指定読み取りを行う
認証済みのアプリケーション要求がfooなどのnamespaceを検索します。特別なペイロードは不要で、通常のnamespaceが脆弱な照合処理に渡されます。
バックエンドが連結してパターン照合
Storeはラベルをドットで連結し、末尾が%のLIKE prefixを使います。区切りを必須にしないため、fooがfoobarに一致する可能性があり、ラベル内のパターン文字も結果を広げます。
隣接namespaceの項目が返る可能性
アプリケーションがnamespaceをテナント境界として扱う場合、検索や一覧取得が別ユーザーの保存項目を返すことがあります。これは読み取り時の機密性問題であり、SQL injectionや書き込み権限の問題ではありません。
更新し、分離テストを再実行
該当する両パッケージを3.1.1以降へ更新します。分離したテストテナントを使い、隣接prefix、リテラルの%と_、suffix、SQLiteの大文字小文字の挙動をテストします。
ソースコード比較:脆弱 vs 堅牢化
脆弱な条件は、連結後のnamespaceで始まる文字列をすべて子孫として扱います。修正では完全一致の条件を追加し、子孫セグメントの前にドットを必須にします。またLIKE用にバックスラッシュ、%、_をエスケープします。上流コミットはlist_namespacesのprefix/suffix条件もセグメント単位の照合へ変更し、SQLite検索も調整しています。これはソースの抜粋であり、モジュール全体の置き換えではありません。
ソース抜粋: libs/checkpoint-postgres/langgraph/store/postgres/base.py
def _prepare_batch_search_queries(op):
ns_condition = "TRUE"
ns_param = None
if op.namespace_prefix:
ns_condition = "store.prefix LIKE %s"
ns_param = (f"{_namespace_to_text(op.namespace_prefix)}%",)
return ns_condition, ns_param
def _escape_like_literal(text: str) -> str:
return text.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
def _namespace_prefix_condition(namespace_prefix: tuple[str, ...]) -> tuple[str, tuple]:
path = _namespace_to_text(namespace_prefix)
condition = r"(store.prefix = %s OR store.prefix LIKE %s ESCAPE '\\')"
return condition, (path, f"{_escape_like_literal(path)}.%")
if op.namespace_prefix:
ns_condition, ns_param = _namespace_prefix_condition(op.namespace_prefix)
エンジニアリング&システム堅牢化チェックリスト
- ✓すべての環境で
langgraph-checkpoint-postgresとlanggraph-checkpoint-sqliteを3.1.1以降に更新してください。 - ✓
fooとfoobarのように、一方が他方のprefixになるテナントラベルを使う回帰テストを追加し、検索結果が要求したnamespaceとその子孫だけであることを確認してください。 - ✓本番と同じDBバックエンドで、
%、_、バックスラッシュ、大小文字だけが異なるラベルをテストしてください。 - ✓
list_namespacesのprefix、suffix、wildcard、空パスをテストし、*が仕様どおり1セグメントだけに一致することを確認してください。 - ✓アプリケーション境界の認可チェックを維持してください。不透明または固定形式のnamespace IDだけではテナント所有者の検証を代替できません。