FlawOpen

flawopen.com/AI Security/langgraph-js-graph-input-control-directive-october-2026

● CWE-20 · CVSS v4 7.6[1] · 高危
安全研究 · FlawOpen

GHSA-wp87-994x-j95x:普通 JSON 被误判为图控制命令

LangGraph.js <1.4.21 可能把普通 JSON 当成控制指令,绕过应用的验证或审批节点。请升级,并在服务器端验证状态。[1]

CVSS 向量CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N[1]
💡 通俗易懂的原理解析 (ELI5)

把图工作流想成火车站:行李必须先检查再上车。受影响版本可能把只写着“Command”的标签误认成有权限的道岔指令。修复后普通对象与 Command 对象会被区分,但应用仍须在每次敏感操作前检查权限。[1], [2]

核心概念与专有名词

GHSA-wp87-994x-j95x
LangChain 于 2026 年 10 月 8 日发布的 High 级安全公告;给出 CVSS 4.0 7.6、CWE-20,且没有已知 CVE。[1]
图输入
传入 LangGraph.js 执行的状态对象;服务器应验证状态并只选取允许字段。[1]
Command
可更新状态或引导执行的 LangGraph.js 对象;普通 JSON 必须仍被视为数据。[2]
控制边界
应用数据被解释为选择节点或改变状态指令的位置。[1]

框架映射

  • 本指南所述弱点的 CWE 参考: CWE-20

攻击执行流程分解

步骤 1

应用接收调用方提供的 JSON

受影响部署把不可信 JSON 直接交给图,而不是在服务器端构造已验证的状态。[1]

步骤 2

数据对象被误认为控制对象

在 1.4.21 之前,单凭 lg_name 就可能让普通对象看起来像 Command。问题在类型识别,而非 JSON 解析。[1], [2]

步骤 3

常规处理流程可能被跳过

该对象可能被当作状态更新或路由指令,从而绕过应用定义的验证或审批节点。[1]

步骤 4

工具权限会放大影响

如果图暴露敏感工具,攻击者输入可能借助应用权限执行工具。应在操作边界再次授权。[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]

源代码对比:漏洞与安全实现

这个精简 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";
}

工程与系统安全加固清单

参考来源

← AI Security Directory →