站点图标 高效码农

LangChain核心库惊现致命漏洞:一个提示词就能窃取你的密钥

LangChain核心库惊现致命漏洞:一个提示词就能窃取你的密钥

摘要:LangChain核心库被发现严重安全漏洞CVE-2025-68664,CVSS评分高达9.3分。该漏洞允许攻击者通过精心构造的LLM输出触发序列化注入,窃取环境变量中的敏感密钥,甚至可能执行任意代码。全球数亿次安装的LangChain应用面临风险,需立即升级至1.2.5或0.3.81版本。


圣诞节前夜,当大多数人沉浸在节日气氛中时,安全研究员却在代码中发现了一个让人背脊发凉的问题。这个被命名为”LangGrinch”的漏洞,藏身于全球最流行的AI应用框架之一——LangChain的核心代码中,已经潜伏了两年半之久。

更令人担忧的是,这不是某个边缘功能的小bug,而是框架核心序列化机制的设计缺陷。攻击者只需要一个精心构造的文本提示,就能让你的AI应用乖乖交出密钥。

这个漏洞到底有多严重?

想象一下这样的场景:你构建了一个AI客服系统,用户通过自然语言与它对话。某天,一个看似普通的提问竟然触发了一连串连锁反应,最终导致你存储在环境变量中的AWS密钥、数据库凭证,甚至API密钥,统统被悄悄发送到了攻击者的服务器上。

这听起来像是科幻电影的情节,但LangGrinch漏洞(CVE-2025-68664)让这一切成为现实。该漏洞被赋予了CVSS 9.3的严重评级,属于CWE-502类别——不受信任数据的反序列化。

受影响范围令人震惊

截至2025年12月,LangChain的下载量统计数据触目惊心:

  • 总下载量:约8.47亿次(pepy.tech数据)
  • 最近一个月:约9800万次下载(pypistats数据)
  • 受影响组件:langchain-core(核心库,被所有LangChain组件依赖)

这意味着,全球范围内可能有成千上万的生产环境正在运行易受攻击的版本。从创业公司的聊天机器人,到大型企业的智能客服系统,从数据分析工具到自动化工作流,几乎所有使用LangChain构建的应用都可能暴露在风险之下。

漏洞是如何被发现的?

这个漏洞的发现过程本身就是一堂生动的安全课。Cyata公司的安全研究员并没有从复杂的攻击链开始,而是从一个简单的问题出发:

AI应用中的信任边界在哪里?开发者真的清楚这些边界吗?

在审计LangChain代码时,研究员采用了”反向工作”的方法——先找到可能造成危害的关键点(比如反序列化函数),然后倒推攻击者如何到达这些点。经过长时间的代码审计,他发现了一个令人意外的事实:

问题不在于某段”坏代码”,而在于”缺失的代码”。

LangChain的dumps()dumpd()函数在序列化用户控制的字典时,完全没有对包含特殊标记'lc'的键进行转义处理。这个看似微小的疏忽,却打开了潘多拉的魔盒。

技术原理:一个标记键引发的灾难

LangChain的序列化机制

LangChain使用一种特殊的内部序列化格式来保存和传输对象。这个格式的核心是一个叫做'lc'的标记键——当字典中包含这个键时,LangChain会将其识别为”这是一个LangChain序列化的对象”,而不是普通的用户数据。

这种设计本身并无问题,问题在于:如何区分真正的LangChain对象和用户提供的、碰巧包含'lc'键的普通字典?

在修复前的版本中,答案是:无法区分

攻击者的突破口

当攻击者能够控制或影响被序列化的数据(比如通过LLM的输出字段additional_kwargsresponse_metadata),他们就能注入包含'lc'标记的恶意字典。当这些数据后续被反序列化时,LangChain会错误地将其当作内部对象处理,进而实例化攻击者指定的类。

让我们看一个简化的流程:

  1. 用户发送提示词 → AI模型处理
  2. 模型输出包含特殊构造的元数据 → 被序列化到日志/缓存
  3. 应用稍后读取并反序列化这些数据 → 触发恶意对象实例化
  4. 密钥被窃取或代码被执行 → 攻击完成

整个过程对终端用户和系统管理员来说完全透明,没有任何明显的异常信号。

三种主要攻击场景

根据官方安全公告,这个漏洞可以导致三种严重后果:

1. 密钥泄露:环境变量不再安全

LangChain的loads()函数支持一种特殊的secret类型,可以在反序列化时从环境变量中解析值。在修复前,secrets_from_env参数默认启用

这意味着什么?攻击者可以构造一个序列化对象,指示系统从环境变量(比如AWS_ACCESS_KEY_IDOPENAI_API_KEY)中读取值。如果这个值随后通过某种方式返回给攻击者——比如包含在LLM的上下文历史中——密钥就此泄露。

更隐蔽的攻击方式是利用langchain_aws包中的ChatBedrockConverse类。这个类在初始化时会发起一个HTTP GET请求,而攻击者可以:

  • 控制请求的目标URL(指向攻击者的服务器)
  • 通过secrets_from_env功能,将环境变量的值插入到HTTP请求头中
  • 在攻击者的服务器上收集这些敏感信息

这是一次完美的盲注攻击——即使攻击者无法看到LLM的任何响应,也能成功窃取密钥。

2. 对象实例化:构造函数中的魔鬼

LangChain的反序列化函数会根据白名单检查,只允许实例化特定命名空间下的类,包括:

  • langchain_core
  • langchain_openai
  • langchain_aws
  • langchain_anthropic
  • 其他生态系统包

虽然大多数类的构造函数是无害的,但总有例外。研究员发现,某些类在实例化时会触发有意义的副作用:

  • 网络请求:如前面提到的ChatBedrockConverse
  • 文件操作:读取或写入本地文件
  • 系统调用:执行其他潜在危险的操作

这些副作用可以被精心编排,构成完整的攻击链。

3. 代码执行:Jinja2模板的后门

白名单中包含的PromptTemplate类支持多种模板格式,其中就有Jinja2。Jinja2是一个强大的模板引擎,但同时也允许在模板中执行任意Python代码。

虽然研究员没有找到仅通过loads()函数直接触发代码执行的路径,但如果反序列化后的对象在后续流程中被渲染(这在正常使用中非常常见),代码执行就会发生。

更值得注意的是,在较早的版本中,Chain类也在白名单中,而这个类具有特殊的功能,可能已经提供了通往模板渲染的直接路径。

12个易受攻击的常见场景

官方安全公告列出了12个已知的易受攻击的使用模式,这些模式在实际应用中极为常见:

实时数据流和日志场景

  1. 事件流(v1版本)astream_events(version="v1")使用了易受攻击的序列化方式(v2版本已修复)
  2. 日志流Runnable.astream_log()在流式传输日志时可能触发漏洞

序列化和反序列化操作

  1. 直接序列化:对不受信任的数据调用dumps()dumpd(),然后用load()loads()反序列化
  2. 直接反序列化:用load()loads()处理不受信任的序列化数据

持久化和缓存场景

  1. 消息历史RunnableWithMessageHistory在保存和加载对话历史时
  2. 向量存储InMemoryVectorStore.load()加载向量数据时
  3. 各类缓存实现:在序列化和反序列化缓存内容时
  4. LangChain Hub:从Hub拉取清单时(hub.pull

其他集成场景

9-12. 公告中列出的其他组件和集成点

最关键的一点是:最常见的攻击向量来自LLM响应本身

通过提示注入,攻击者可以影响模型输出中的additional_kwargsresponse_metadata字段。这些字段在流式操作、日志记录、缓存等场景中会被序列化和反序列化,从而触发漏洞。

这正是AI安全与传统安全的交汇点——LLM的输出必须被视为不受信任的输入。如果框架将这些输出的某些部分当作结构化对象处理,攻击者就能够塑造这些内容。

如何检查你的应用是否受影响?

第一步:检查langchain-core版本

运行以下命令查看当前安装的版本:

pip show langchain-core

如果版本早于0.3.811.2.5,你的应用存在漏洞。

需要特别注意的是,即使你只安装了langchainlangchain-community等上层包,它们也会依赖langchain-core。务必确认实际运行环境中的版本。

第二步:审查代码中的高危模式

即使你已经更新到最新版本,也应该审查代码中是否存在以下高危模式:

高危代码特征清单

  • 使用astream_events(version="v1")(应改用v2版本)
  • 调用Runnable.astream_log()
  • 对可能包含用户输入或LLM输出的数据调用dumps()/dumpd()
  • 使用load()/loads()处理来自外部的序列化数据
  • 从LangChain Hub拉取内容(hub.pull
  • 使用消息历史、向量存储加载、缓存等功能

第三步:评估数据流路径

追踪你的应用中,哪些数据流可能包含不受信任的内容:

  1. 直接用户输入:聊天消息、上传的文档、API请求参数
  2. LLM输出:模型生成的文本、工具调用结果、元数据字段
  3. 外部工具返回值:网络搜索结果、数据库查询结果、第三方API响应
  4. 检索的文档:从向量数据库或文档存储中检索的内容

如果这些数据在某个环节被序列化,然后在另一个环节被反序列化,就存在潜在风险。

第四步:检查secrets_from_env配置

搜索代码中所有调用load()loads()的位置,检查是否显式设置了secrets_from_env=False。在修复前的版本中,这个参数默认为True,即使升级后,也应该明确禁用此功能,除非你完全信任序列化输入的来源。

立即采取的修复措施

紧急修复:升级到安全版本

这是降低风险最快速有效的方法。运行以下命令:

pip install --upgrade langchain-core

确保升级到的版本为:

  • 0.3.81或更高版本(0.3.x系列)
  • 1.2.5或更高版本(1.x系列)

如果你的环境中使用了锁定文件(如requirements.txtPipfile.lockpoetry.lock),记得更新这些文件并在所有部署环境中同步更新。

代码级防护措施

1. 明确禁用环境变量密钥解析

在所有调用loads()的地方,显式设置:

from langchain_core.load import loads

# 即使在安全版本中,也应明确禁用
data = loads(serialized_data, secrets_from_env=False)

2. 升级事件流版本

将所有astream_events调用从v1升级到v2:

# 旧代码(易受攻击)
async for event in runnable.astream_events(input, version="v1"):
    process(event)

# 新代码(安全)
async for event in runnable.astream_events(input, version="v2"):
    process(event)

v2版本使用了更安全的序列化机制,不受此漏洞影响。

3. 实施输入验证

对所有可能影响序列化数据的输入进行严格验证:

  • 过滤或转义包含'lc'键的用户提供的字典
  • 对LLM输出的元数据字段进行清洗
  • 限制可以被序列化的字段类型和内容

4. 最小权限原则

  • 不要在环境变量中存储敏感密钥,改用专用的密钥管理服务
  • 运行AI应用的进程应该使用最小必需的权限
  • 隔离不同信任级别的组件,避免高权限服务直接处理不受信任的输入

生产环境清单

针对生产环境,建议执行以下完整的安全审查:

部署前检查

  • [ ] 确认所有环境(开发、测试、生产)都已升级到安全版本
  • [ ] 审查CI/CD流水线中的依赖版本
  • [ ] 更新容器镜像和虚拟机模板
  • [ ] 检查Lambda函数或其他无服务器部署的依赖

配置审查

  • [ ] 禁用不必要的序列化功能
  • [ ] 审查所有使用loads()的代码点
  • [ ] 确认日志和事件流配置的安全性
  • [ ] 评估缓存机制的安全性

监控和响应

  • [ ] 设置异常反序列化行为的监控告警
  • [ ] 审查近期日志中是否有可疑的序列化活动
  • [ ] 准备应急响应计划
  • [ ] 通知相关团队和利益相关者

LangChainJS也受影响

基于同一份研究报告,LangChain的JavaScript/TypeScript版本也发现了类似的漏洞:

  • CVE编号:CVE-2025-68665
  • GitHub安全公告:GHSA-r399-636x-v7f6
  • 漏洞机制:相同的'lc'标记混淆问题

如果你的组织同时运行Python和JavaScript版本的LangChain应用,需要同时修复两个平台。这也提醒我们:基于标记的序列化、不受信任的模型输出、以及后续的反序列化,这是一个跨生态系统的反复出现的风险模式。

这个漏洞的更深层含义

LangGrinch不仅仅是”库中的一个bug”,它是一个重要的案例研究,揭示了AI应用安全的新挑战:

信任边界的模糊化

传统应用中,我们清楚地知道哪些是用户输入(不可信),哪些是系统内部数据(可信)。但在AI应用中,这条界限变得模糊:

  • LLM的输出看起来是”系统生成的”,但实际上可能受到提示注入的影响
  • 工具的返回值可能来自外部API,包含不受信任的内容
  • 检索的文档可能来自用户上传,嵌入恶意内容

你的应用可能在反序列化它认为是自己安全生成的数据,但这些数据实际上包含了受不受信任来源影响的字段。

单个保留键的威力

一个简单的内部标记('lc'键)成为了整个安全体系的枢纽点。当用户控制的数据碰巧包含这个标记时,整个信任模型崩溃。

这教会我们:在设计序列化格式时,必须有明确的转义机制,确保用户数据永远不会被误认为是系统结构。

AI编排层成为新的攻击面

过去两年,我们见证了大量AI应用框架的涌现。这些框架处理序列化、工具执行、缓存、追踪等”管道工作”。但这些”管道”不再只是辅助功能——它们现在是安全边界的一部分

序列化格式、编排流水线、工具执行链,都可能成为攻击者的突破口。框架开发者和使用者都需要重新审视这些组件的安全性。

常见问题解答

我的应用只在内网运行,还需要担心吗?

需要。这个漏洞最常见的触发路径是通过LLM输出的字段,而这些字段可能受到提示注入的影响。即使你的应用不直接暴露在互联网上,只要:

  1. 用户可以输入提示词
  2. 应用会处理LLM的响应元数据
  3. 这些元数据会被序列化和反序列化

就存在风险。内网员工、恶意用户、甚至是无意中输入特殊内容的合法用户,都可能触发漏洞。

我使用的是LangChain的托管服务,还需要手动更新吗?

这取决于服务提供商。如果你使用的是LangSmith或其他官方托管服务,LangChain团队很可能已经在后端更新了。但是:

  • 如果你自己部署了LangChain应用(即使使用了托管的LLM API),需要手动更新
  • 如果你使用第三方平台运行LangChain代码,需要确认他们是否已更新
  • 检查你的依赖锁定文件,确保不会在下次部署时回退到旧版本

更新后需要修改代码吗?

大多数情况下不需要。修复主要在框架内部:

  • dumps()/dumpd()现在会自动转义包含'lc'的用户字典
  • secrets_from_env的默认值改为False

但建议进行以下可选的代码改进:

  • 显式设置secrets_from_env=False以增强代码可读性
  • astream_events从v1升级到v2
  • 添加额外的输入验证层

我能检测到正在进行的攻击吗?

直接检测很困难,因为攻击可能完全融入正常的应用行为。但可以监控以下异常信号:

  • 不寻常的网络连接(特别是到未知外部服务器的请求)
  • 环境变量访问模式的异常
  • 序列化/反序列化错误的突然增加
  • LLM响应中包含格式异常的元数据字段

设置日志记录和异常检测机制是长期安全策略的一部分。

这个漏洞会导致我的整个系统被攻破吗?

不一定,这取决于你的应用架构和权限配置:

  • 最坏情况:如果你的LangChain应用运行在高权限环境中,环境变量包含关键密钥(数据库凭证、云服务密钥、私钥等),攻击者窃取这些密钥后可能获得更广泛的系统访问权限。

  • 较好情况:如果你遵循了最小权限原则,使用了专门的密钥管理服务,并且应用运行在隔离环境中,影响可以被控制在较小范围。

这也是为什么纵深防御如此重要——单个漏洞不应该能够摧毁整个安全体系。

我应该暂停我的AI应用吗?

如果你已经确认在运行易受攻击的版本,建议:

立即行动场景

  • 应用处理高度敏感数据(医疗、金融、个人身份信息)
  • 环境变量包含关键的生产密钥
  • 应用允许匿名或不受信任的用户输入

可以稍作延迟的场景

  • 内部测试或开发环境
  • 低风险的演示应用
  • 已经实施了额外安全控制的环境

但无论如何,更新应该是最高优先级的任务,应在数天内完成,而不是数周或数月。

LangChain团队的响应如何?

根据披露时间线,LangChain团队的响应非常迅速和专业:

  • 12月4日:漏洞报告提交(通过Huntr平台)
  • 12月5日:LangChain维护者确认
  • 12月24日:补丁发布,CVE和安全公告同步发布

从发现到修复仅用了20天,这在开源项目中是非常快的响应速度。

此外,LangChain不仅修复了具体的bug,还加强了默认配置(将secrets_from_env改为False),这显示了对安全性的重视。

这次漏洞的赏金是多少?

LangChain项目为这个发现颁发了4000美元的漏洞赏金。根据Huntr平台(LangChain运营漏洞赏金计划的平台)的记录,这是该项目有史以来授予的最高金额,之前的赏金最高为125美元。

这个数字反映了漏洞的严重性和影响范围。

面向未来:AI应用的安全治理

LangGrinch漏洞凸显了一个更大的问题:大多数组织目前无法快速、自信地回答以下问题:

  • 我们在哪里使用了AI代理?
  • 生产环境部署了哪些版本?
  • 哪些服务有权访问敏感密钥?
  • LLM输出在哪些地方跨越了信任边界?

这不是”开发者的问题”,而是可见性和治理的问题

当圣诞周发布一个严重的CVE公告时,目标不应该是英雄主义的紧急响应,而应该是基于真实清单和强制性保护措施的冷静、可控的响应。

建立AI应用的可见性

成功的AI安全治理始于清晰的可见性:

  • 发现所有运行AI代理的地方(IDE、CI、服务、工作任务、托管代理)
  • 追踪框架、包和版本的使用情况
  • 识别数据流和信任边界
  • 映射权限和密钥访问模式

基于风险的优先级排序

不是所有的AI应用都有相同的风险档案。需要识别:

  • 哪些应用面向互联网
  • 哪些应用接触敏感密钥
  • 哪些应用运行在高权限环境
  • 哪些应用处理不受信任的输入(结构化字段、元数据、工具输出、流式事件、缓存数据)

强制性控制和安全护栏

即使在所有依赖都完全更新之前,也可以降低暴露风险:

  • 推动更安全的默认配置(最小权限、隔离边界、策略检查)
  • 对高风险模式设置护栏(反序列化不受信任的数据、宽松的对象恢复、不安全的流-缓存-再恢复流程)
  • 在不受信任的上下文中限制敏感能力(通过环境的密钥访问、高权限工具执行、在特权工作进程中运行危险代码路径)

可审计的治理流程

让”安全的AI代理使用”变得可重复、可审计、难以偏离:

  • 定义批准的框架、版本和配置的策略
  • 追踪例外情况,记录负责人和理由
  • 监控配置漂移和高风险功能使用,保持支持安全审查和合规性的审计跟踪

最后的建议

LangGrinch是AI应用时代的一个警钟。随着AI代理框架成为关键基础设施,我们需要用同样严格的安全标准来对待它们。

对于开发者:

  • 立即更新langchain-core到安全版本
  • 审查你的代码中是否存在高危模式
  • 将LLM输出始终视为不受信任的输入
  • 实施纵深防御,不要依赖单一的安全控制

对于安全团队:

  • 建立AI应用和框架使用的清单
  • 制定AI安全的响应流程
  • 投资于AI应用的可见性和治理工具
  • 培训开发团队关于AI特有的安全风险

对于组织领导者:

  • 认识到AI应用安全不是可选项
  • 为安全工作分配适当的资源和优先级
  • 建立跨部门的AI安全协作机制
  • 在快速创新和安全之间找到平衡

这个圣诞节,安全研究员送给开源社区的礼物是一个及时的漏洞披露。现在轮到我们每个人采取行动,确保我们的AI应用不会在节日后成为攻击者的礼物。

立即检查你的LangChain版本,升级到安全版本,并审查你的安全架构。AI的未来取决于我们今天构建的安全基础。

退出移动版