LangChain Vulnerable to Template Injection via Attribute Access in Prompt Templates · CVE-2025-65106
漏洞详情
包管理器: pip 受影响包: langchain-core (pip)
受影响版本:
-
= 1.0.0, <= 1.0.6
- <= 0.3.79
已修复版本:
- 1.0.7
- 0.3.80
描述
背景
LangChain的提示模板系统存在一个模板注入漏洞,允许攻击者通过模板语法访问Python对象的内部属性。此漏洞影响那些接受来自不可信来源的模板字符串(而不仅仅是模板变量)的应用程序,涉及ChatPromptTemplate及相关提示模板类。模板允许属性访问(.)和索引([]),但不支持方法调用(())。属性访问和索引的组合可能根据传递给模板的对象类型实现利用。当模板变量是简单字符串(常见情况)时,影响有限。然而,当使用带有聊天消息对象的MessagesPlaceholder时,攻击者可以遍历对象属性和字典查找(例如__globals__)以获取敏感数据,如环境变量。该漏洞特指应用程序从不可信来源接受模板字符串(结构)的情况,而不仅仅是模板变量(数据)。大多数应用程序要么不使用模板,要么使用硬编码模板,因此不受影响。
受影响组件:
- langchain-core 包
- 模板格式:
- 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()来从模板字符串中提取变量名。此方法返回完整的字段表达式,包括属性访问语法:1 2 3 4 5from string import Formatter template = "{msg.__class__} and {x}" print([var_name for (_, var_name, _, _) in Formatter().parse(template)]) # 返回: ['msg.__class__', 'x']提取的名称未经验证以确保是简单的标识符。因此,包含属性遍历和索引表达式(例如
{obj.__class__.__name__}或{obj.method.__globals__[os]})的模板字符串被接受并在后续格式化期间被求值。虽然f-string模板不支持带()的方法调用,但它们支持[]索引,这可能允许通过像__globals__这样的字典进行遍历以访问敏感对象。 -
Mustache 模板: 设计上,使用
getattr()作为回退以支持访问对象上的属性(例如,User对象上的{{user.name}})。然而,我们决定将其限制为更简单的原语,这些原语是dict、list和tuple类型的子类,作为防御性加固,因为不可信的模板可能利用属性访问来触及任意对象上的内部属性(如__class__)。 -
Jinja2 模板: Jinja2默认的
SandboxedEnvironment阻止双下划线属性(例如__class__),但允许访问对象上的其他属性和方法。虽然LangChain中的Jinja2模板通常与受信任的模板字符串一起使用,但作为深度防御措施,我们限制了环境以阻止对传递给模板的对象的所有属性和方法访问。
受影响人群
高风险场景 如果您的应用程序符合以下情况,则受到影响:
- 接受来自不可信来源(用户输入、外部API、数据库)的模板字符串
- 基于用户提供的模式动态构建提示模板
- 允许用户自定义或创建提示模板
示例易受攻击代码:
|
|
低风险/无风险场景 如果符合以下情况,则不受影响:
- 模板字符串在应用程序代码中是硬编码的
- 模板字符串仅来自受信任、受控的来源
- 用户只能提供模板变量的值,而不能控制模板结构本身
示例安全代码:
|
|
修复方案
F-string 模板
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模板。虽然我们已经加固了Jinja2实现,但模板引擎的性质使得全面的沙箱化具有挑战性。最安全的方法是仅在控制模板源时使用Jinja2模板。
重要提醒: 许多应用程序不需要提示模板。模板对于变量替换和动态逻辑(if语句、循环、条件)很有用。然而,如果您正在构建聊天机器人或对话应用程序,通常可以直接使用消息对象(例如,HumanMessage、AIMessage、ToolMessage)而无需模板。直接构造消息完全避免了与模板相关的安全问题。
补救措施
立即行动
- 审计您的代码,查找任何模板字符串来自不可信来源的位置
- 更新到langchain-core的已修复版本
- 审查模板使用情况,确保模板结构与用户数据的分离
最佳实践
- 考虑您是否真的需要模板 - 许多应用程序可以直接使用消息对象(
HumanMessage、AIMessage等)而无需模板 - 将Jinja2保留给受信任的来源 - 仅在完全控制模板内容时使用Jinja2模板
参考信息
- GHSA-6qv9-48xg-fc7f
- langchain-ai/langchain@c4b6ba2
- langchain-ai/langchain@fa7789d
- https://nvd.nist.gov/vuln/detail/CVE-2025-65106
漏洞信息
- CWE 弱点: CWE-1336 - 模板引擎中使用的特殊元素的不当中和
- 严重等级: 高
- CVSS 总体评分: 8.3
- CVSS v4 向量: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N
- EPSS 评分: 0.045% (第13百分位)