FlawOpen

flawopen.com/AI Security/langgraph-js-custom-auth-cross-user-store-access

● CWE-639 / CWE-863 · CVSS v4 8.6[1] · 高
セキュリティ研究 · FlawOpen

LangGraph JS Auth:Store のユーザー間アクセス

langgraph-api 0.15.0未満では、JS/TSカスタム認証が書き換えたStore namespaceを失い、他ユーザーのデータへアクセス可能でした。0.15.0へ更新してください。[1], [2]

CVSS ベクトルCVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N[1]
💡 わかりやすい解説 (ELI5)

図書館で司書が利用証を確認し、別の窓口に本の取得を頼む場面を考えてください。別窓口はあなたの棚番号を書き込みますが、引き継ぎで変更が失われ、訪問者が最初に指定した棚から本を取ってしまいます。影響を受ける JavaScript/TypeScript 認証経路では、認可ランタイムと Store 操作の間で namespace の書き換えが失われる可能性がありました。修正では認可済み namespace を引き継ぎ、Store の使用前に検証します。[1]

主要な概念と専門用語

GHSA-4hm6-w6qq-w73v
2026年9月28日に公開された LangGraph の高重要度アドバイザリです。CVE は割り当てられていません。対象パッケージは langgraph-api で、0.15.0 で修正されています。[1]
Store namespace
LangGraph Store のレコードをまとめる階層名です。データ分離のためユーザーやテナントの識別子を含めることがあります。[1]
カスタム認可ハンドラー
認証済みリクエストのリソースアクセス可否を決め、Store 操作前に namespace を書き換えることもできるアプリケーションコードです。[1]
CWE-639 / CWE-863
ユーザー制御キーによる認可回避と不適切な認可です。ハンドラーが指定した namespace 制限を適用できない問題です。[1], [3], [4]

フレームワーク対応

ステップ・バイ・ステップの攻撃フロー

ステップ 1

デプロイが条件に該当するか確認

langgraph-api が >=0.1.2 かつ <0.15.0 で、サーバーが JavaScript または TypeScript のカスタム認証ハンドラーを使うか確認します。[1]

ステップ 2

namespace の書き換えを特定

ハンドラーが範囲外の要求を拒否せず、認証済みユーザーの識別子を含める、または強制するため要求 namespace を変更します。[1]

ステップ 3

認可結果がランタイム境界を越える

影響を受けるバージョンでは namespace の変更が Store 操作へ伝わらない可能性があり、要求者が指定した元の namespace が使われることがあります。[1]

ステップ 4

認証済みユーザーが別の namespace を指定

一般ユーザーが自身の namespace 外の Store レコードに対する操作を要求できます。アドバイザリでは読み取り、上書き、検索、削除が挙げられています。[1]

ステップ 5

更新するか未許可 namespace を拒否

langgraph-api>=0.15.0 に更新します。すぐ更新できない場合は、すべての Store 操作で未許可 namespace を拒否し、Store が認可済み namespace だけを受け取ることを確認します。[1], [2]

根本原因の分析 (Root Cause)

LangGraph メンテナーが2026年9月28日に公開した GHSA は、langgraph-api >=0.1.2 かつ <0.15.0 の不具合を説明しています。影響には次の条件がすべて必要です。JavaScript または TypeScript のカスタム認証を使用し、Store 認可ハンドラーが現在のユーザーにデータを制限するため要求 namespace を書き換え、通常の認証済みユーザーが Store 操作を送信でき、その認可経路を複数ユーザーのデータが通ることです。アドバイザリによれば、Python のカスタム認証ハンドラーは対象外です。また、JavaScript/TypeScript ハンドラーが namespace を書き換えるのではなく未許可リクエストを拒否する場合も対象外です。ハンドラーによる namespace の変更がランタイム境界で失われ、Store 操作が元の要求 namespace を使う可能性がありました。認証済みユーザーが許可された namespace 外のレコードを読み取り、上書き、検索、削除できるおそれがあります。これはログインを回避するものでも未認証のリモート攻撃でもありません。アドバイザリは High、CVSS 4.0 8.6 と評価し、CWE-639 と CWE-863 を割り当てています。0.15.0 はハンドラーの変更を境界越しに渡し、結果の namespace を検証し、不正または安全に適用できない変更を拒否します。アップグレードまでの回避策は、すべての Store 操作で未許可 namespace を拒否することです。コードはデータフローを示す簡略 TypeScript 例であり、SDK の実ソースではありません。[1]

ソースコード比較:脆弱 vs 堅牢化

この簡略 TypeScript 例は境界の契約を示すもので、関数名と結果の形式は説明用です。LangGraph SDK の実ソースではありません。アドバイザリは JS/TS の認可変更が Store 操作前に失われる可能性を確認していますが、この内部実装そのものは公開していません。したがって脆弱側は、Store が認可済み namespace ではなく要求 namespace を使うという、文書化された不変条件のみを示します。修正版は認可結果を受け取り検証します。メンテナーが示す回避策は、すべての Store 操作で未許可 namespace を書き換えずに拒否することです。[1]

ソース抜粋: LangGraph API の認可と Store の境界 — 簡略化した契約例

脆弱な実装
type StoreRequest = { namespace: string[]; key: string };
type AuthorizationResult = { allowed: boolean; namespace: string[] };

async function readStore(userId: string, request: StoreRequest) {
  const authorization = await authorizeStore(userId, request); // Illustrative bridge contract.
  return store.get(request.namespace, request.key); // The bridge drops the authorized result.
}
堅牢化されたセキュアパッチ
type StoreRequest = { namespace: string[]; key: string };
type AuthorizationResult = { allowed: boolean; namespace: string[] };

async function readStore(userId: string, request: StoreRequest) {
  const authorization = await authorizeStore(userId, request); // Illustrative bridge contract.
  if (!authorization.allowed) throw new Error("forbidden");
  const namespace = validateAuthorizedNamespace(userId, authorization.namespace);
  return store.get(namespace, request.key); // Apply the authorized result.
}

エンジニアリング&システム堅牢化チェックリスト

参考資料

← AI Security Directory →