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]

프레임워크 매핑

  • 이 가이드에서 설명하는 약점의 CWE 참조: CWE-639 CWE-863

단계별 공격 실행 흐름

단계 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 사용자 지정 인증 핸들러는 영향을 받지 않습니다. 또한 namespace를 재작성하지 않고 권한 없는 요청을 거부하는 JavaScript/TypeScript 핸들러도 영향이 없습니다. 핸들러의 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 →