LangChain提示模板注入漏洞详解(CVE-2025-65106)
漏洞概述
一个模板注入漏洞存在于LangChain的提示模板系统中,允许攻击者通过模板语法访问Python对象的内部属性。该漏洞影响那些接受来自非受信源的模板字符串(而不仅仅是模板变量)的应用程序,主要涉及ChatPromptTemplate及相关提示模板类。
关键点:
- 模板允许属性访问(
.)和索引([]),但不允许方法调用(())。 - 当模板变量是简单字符串(常见情况)时,影响有限。
- 然而,当使用
MessagesPlaceholder并传入聊天消息对象时,攻击者可以通过对象属性和字典查找(例如__globals__)遍历至敏感数据,如环境变量。 - 该漏洞特别要求应用程序从非受信源接受模板字符串(结构本身),而不仅仅是模板变量(数据)。
受影响组件
- 包:
langchain-core(pip) - 受影响版本:
>= 1.0.0, <= 1.0.6<= 0.3.79
- 已修复版本:
1.0.70.3.80
- 受影响的模板格式:
- F-string模板 (
template_format="f-string") - 漏洞已修复 - Mustache模板 (
template_format="mustache") - 已进行防御性加固 - Jinja2模板 (
template_format="jinja2") - 已进行防御性加固
- F-string模板 (
漏洞影响
能够控制模板字符串(而不仅仅是模板变量)的攻击者可以:
- 通过属性遍历访问Python对象属性和内部属性。
- 从对象内部提取敏感信息(例如
__class__、__globals__)。 - 根据传递给模板的对象,可能升级为更严重的攻击。
攻击向量示例
1. F-string 模板注入(修复前)
|
|
2. Mustache 模板注入(加固前)
|
|
3. Jinja2 模板注入(加固前)
|
|
根本原因
F-string 模板
实现使用了Python的string.Formatter().parse()来从模板字符串中提取变量名。此方法返回完整的字段表达式,包括属性访问语法。提取的名称未经验证以确保它们是简单的标识符。
Mustache 模板
设计上使用getattr()作为回退以支持访问对象上的属性。然而,我们决定将其限制为仅支持继承自dict、list和tuple类型的简单原语,以作为防御性加固。
Jinja2 模板
Jinja2的默认SandboxedEnvironment会阻止双下划线属性,但允许访问对象上的其他属性和方法。作为纵深防御措施,我们限制了环境,阻止所有对传递给模板的对象的属性和方法访问。
受影响用户
高风险场景
如果您的应用程序符合以下情况,则受影响:
- 从非受信源(用户输入、外部API、数据库)接受模板字符串。
- 基于用户提供的模式动态构建提示模板。
- 允许用户自定义或创建提示模板。
易受攻击的代码示例:
|
|
低风险/无风险场景
如果符合以下情况,则不受影响:
- 模板字符串在您的应用程序代码中是硬编码的。
- 模板字符串仅来自受信任的、受控的来源。
- 用户只能提供模板变量的值,而不能控制模板结构本身。
安全的代码示例:
|
|
修复方案
F-string 模板
添加了严格的验证以强制执行变量名必须是有效的Python标识符:
- 拒绝语法如
{obj.attr}、{obj[0]}或{obj.__class__}。 - 只允许简单的变量名:
{variable_name}。
修复后示例:
|
|
Mustache 模板(防御性加固)
作为防御性加固,限制了Mustache模板的支持以减少攻击面:
- 用严格的类型检查替换了
getattr()回退。 - 只允许遍历到dict、list和tuple类型。
- 阻止对任意Python对象的属性访问。
加固后示例:
|
|
Jinja2 模板(防御性加固)
作为防御性加固,显著限制了Jinja2模板的能力:
- 引入了
_RestrictedSandboxedEnvironment,阻止所有属性/方法访问。 - 只允许从上下文字典中进行简单的变量查找。
- 在任何属性访问尝试时都会引发
SecurityError。
加固后示例:
|
|
重要建议:由于Jinja2的表现力和完全沙盒化的难度,我们建议仅将Jinja2模板用于受信任的源。如果您需要从非受信任的用户接受模板字符串,请使用具有新限制的f-string或mustache模板。
修复建议
立即行动
- 审计代码:检查任何从非受信源获取模板字符串的位置。
- 更新版本:将
langchain-core更新至已修复版本。 - 审查模板使用:确保模板结构和用户数据之间的分离。
最佳实践
- 考虑是否真的需要模板:许多应用程序可以直接使用消息对象(
HumanMessage、AIMessage等)而无需模板。 - 仅为受信任的源保留Jinja2:仅在完全控制模板内容时使用Jinja2模板。
- 重要提醒:许多应用程序不需要提示模板。模板对于变量替换和动态逻辑(if语句、循环、条件)很有用。然而,如果您正在构建聊天机器人或对话应用程序,通常可以直接使用消息对象而无需模板。直接的消息构造可以完全避免与模板相关的安全问题。
参考资料
- GHSA-6qv9-48xg-fc7f
- 提交记录:langchain-ai/langchain@c4b6ba2 和 langchain-ai/langchain@fa7789d
- NVD漏洞详情:https://nvd.nist.gov/vuln/detail/CVE-2025-65106
漏洞评分
- CVSS总体评分:8.3(高危)
- EPSS评分:0.059%(第18百分位)
- 相关弱点:CWE-1336 - 模板引擎中特殊元素的不当中和