flawopen.com/AI Security/langgraph-js-graph-input-control-directive-october-2026
GHSA-wp87-994x-j95x: JSON을 그래프 명령으로 오인
LangGraph.js <1.4.21은 일반 JSON을 제어 지시로 처리해 검증 또는 승인 노드를 건너뛸 수 있었습니다. 업그레이드하고 서버에서 상태를 검증하세요.[1]
그래프를 기차역이라고 생각해 보세요. 짐은 기차에 싣기 전에 검사해야 합니다. 취약한 버전에서는 “Command”라고 적힌 꼬리표를 선로 변경 권한이 있는 명령으로 오인할 수 있었습니다. 수정 버전은 일반 객체와 Command 객체를 구분하지만, 민감한 작업마다 권한을 확인해야 합니다.[1], [2]
핵심 개념 및 용어
GHSA-wp87-994x-j95x- LangChain이 2026년 10월 8일 공개한 High 보안 권고입니다. CVSS 4.0 7.6, CWE-20이며 알려진 CVE는 없습니다.[1]
Graph 입력- LangGraph.js 실행에 전달하는 상태 객체입니다. 서버에서 검증하고 허용된 필드만 선택해야 합니다.[1]
Command- 상태를 갱신하거나 실행 흐름을 지정하는 객체입니다. 일반 JSON은 데이터로 남아야 합니다.[2]
제어 경계- 애플리케이션 데이터가 노드 선택 또는 상태 변경 지시로 해석되는 경계입니다.[1]
프레임워크 매핑
- 이 가이드에서 설명하는 약점의 CWE 참조: CWE-20
단계별 공격 실행 흐름
호출자가 제어하는 JSON을 받음
영향받는 배포는 검증된 상태를 서버에서 만들지 않고 신뢰할 수 없는 JSON을 그래프에 직접 전달합니다.[1]
일반 처리 경로가 생략될 수 있음
객체가 상태 갱신 또는 라우팅 지시로 처리되어 애플리케이션 정의 검증·승인 노드를 우회할 수 있습니다.[1]
도구 권한에 따라 영향이 커짐
민감 도구가 연결되어 있으면 애플리케이션 권한으로 실행될 수 있습니다. 작업 경계에서 다시 권한을 확인하세요.[1]
근본 원인 분석 (Root Cause)
권고 대상은 @langchain/langgraph >=0.2.23 및 <1.4.21입니다. 애플리케이션이 신뢰할 수 없는 JSON을 그래프에 직접 전달하고 검증 또는 권한 확인을 일반 실행 경로에 맡길 때 영향을 받습니다. 수정 PR에 따르면 기존 isCommand는 lg_name 필드만으로 값을 식별했기 때문에 일반 JSON 객체가 Command로 오인될 수 있었습니다. 그러면 애플리케이션의 검증 또는 승인 노드보다 먼저 update나 goto가 적용될 수 있습니다. 민감 도구가 노출되면 애플리케이션 권한으로 무단 실행이 가능하다고 권고는 설명합니다. 1.4.21은 일반 객체를 거부하면서 실제 Command 인스턴스는 계속 처리합니다. 서버 측 상태 생성, 허용 필드 제한, 각 민감 작업의 권한 확인을 대체하지 않습니다. CWE-20, High, CVSS 4.0 7.6이며 알려진 CVE는 없습니다.[1], [2]
소스 코드 비교: 취약한 구현 vs 보안 패치
이 축약 TypeScript 예시는 PR #2966의 변경을 반영합니다. lg_name 필드만으로 일반 객체를 Command로 판정하지 않습니다. 실제 소스의 그대로인 발췌나 전체 구현은 아닙니다. 수정 후 파싱된 JSON은 일반 상태 경로를 따르고 실제 Command 객체만 그래프 흐름을 제어합니다. 객체 모양을 권한 확인으로 사용하지 마세요. 서버에서 허용 목록으로 상태를 만들고 민감 작업마다 별도로 권한을 확인하세요.[2]
소스 코드 발췌: LangGraph.js Command 판별기의 축약 동작 예시이며 전체 소스 코드가 아닙니다
type CommandLike = { lg_name: string; goto?: unknown; update?: unknown };
function isCommand(value: unknown): value is CommandLike {
return typeof value === "object" && value !== null &&
"lg_name" in value && value.lg_name === "Command";
}
type CommandLike = { lg_name: string; goto?: unknown; update?: unknown };
function isPlainObject(value: object): boolean {
const prototype = Object.getPrototypeOf(value);
return prototype === Object.prototype || prototype === null;
}
function isCommand(value: unknown): value is CommandLike {
return typeof value === "object" && value !== null &&
!isPlainObject(value) &&
"lg_name" in value && value.lg_name === "Command";
}
엔지니어링 및 시스템 보안 강화 체크리스트
- ✓@langchain/langgraph를 1.4.21 이상으로 업그레이드하고 잠금 파일 및 배포 산출물의 실제 버전을 확인합니다.[1], [2]
- ✓요청 JSON을
graph.invoke()또는graph.stream()에 직접 전달하지 말고 허용 필드로 서버에서 상태를 구성합니다.[1] - ✓제어 객체를 호출자 제어 상태와 분리하고 비슷한 필드명이 든 JSON도 일반 입력으로 처리되는 회귀 테스트를 추가합니다.[2]
- ✓각 민감 도구와 부작용을 인증된 주체와 리소스 범위에 따라 작업 경계에서 승인합니다.[1]
- ✓신뢰할 수 없는 JSON을 그래프에 전달하는 통합 테스트를 추가하고, 인증된 주체가 대상 리소스 권한이 없으면 민감 도구의 테스트 스텁이 호출되지 않는지 확인합니다.[1], [2]