当前位置: 首页 > news >正文

LangChain 昨天悄悄打了个安全补丁,你的 Agent 可能正在被“越狱“

2026 年 4 月 8 日,一个普通的周三,LangChain-core 一天之内发了两个版本:0.3.84 和 1.2.28。

大部分人刷到 changelog 的时候会直接跳过——又是修 bug 的小版本。

但这次不一样。两个版本有一条一模一样的改动:sanitize prompts。CVE 编号 2026-4539。

这是安全补丁。说明在此之前,LangChain 的 PromptTemplate 存在一个真实可利用的注入漏洞。你可能已经在线上跑着用了 PromptTemplate 的 Agent。

一、问题出在哪:两行源码的故事

先说结论再展开原理。

LangChain 的 PromptTemplate 用的是 Python 的str.format_map做变量替换。这个方法有个特点:它不区分{}是你写在模板里的,还是用户输入带进来的。只要字符串里有{变量名},它就会尝试替换

类比一下:这就像餐厅有个规定"单据里括号里的都是厨师指令",结果顾客在菜名里写了个括号,厨师就真的按顾客的意思操作了。

来看 LangChain-core 0.3.83(补丁之前)的核心格式化逻辑:

# langchain_core/prompts/prompt.py(补丁前简化版) class PromptTemplate(StringPromptTemplate): def format(self, **kwargs: Any) -> str: kwargs = self._merge_partial_and_user_variables(**kwargs) return DEFAULT_FORMATTER_MAPPING[self.template_format]( self.template, **kwargs ) # DEFAULT_FORMATTER_MAPPING["f-string"] 最终调用: def format(self, template: str, **kwargs: Any) -> str: return template.format_map(kwargs) # ← 问题就在这里

就这一行:template.format_map(kwargs)

用户传进来的值,没有任何处理,直接喂给了format_map

二、攻击场景还原:从读取变量到泄露 API Key

设定:你做了一个翻译服务,模板长这样:

from langchain_core.prompts import PromptTemplate template = """ 你是一个专业翻译,请将原文翻译成英文。 规则:{rules} 原文:{user_text} """ prompt = PromptTemplate( input_variables=["rules", "user_text"], template=template )

正常请求:user_text="你好世界",一切正常。

攻击者请求:user_text="{rules}"

执行template.format_map({"rules": "保持专业语气", "user_text": "{rules}"})时,发生了两轮替换:

• 第一轮:{user_text}{rules}(用户注入的字符串)

• 第二轮:{rules}保持专业语气

原文那栏显示了 rules 的值。这还只是轻量版。

更危险的变体:

# Python 的 str.format_map 支持属性访问和下标访问 user_text = "{config.OPENAI_API_KEY}" # 如果你无意中把配置对象传进了 kwargs(线上代码里不罕见): result = prompt.format( rules="保持专业语气", user_text=user_text, config=app_config # ← 假设在某个中间件里统一注入了上下文 ) # 输出里会包含你的 OPENAI_API_KEY print(result) # 你是一个专业翻译... # 规则:保持专业语气 # 原文:sk-proj-xxxxxxxxxxxxxxxxxx str: """把用户输入里的 { 和 } 转义,阻止二次解析""" return value.replace("{", "{{").replace("}", "}}") def format(self, **kwargs: Any) -> str: kwargs = self._merge_partial_and_user_variables(**kwargs) if self.template_format == "f-string": sanitized = { k: _sanitize_value_for_fstring(str(v)) if isinstance(v, str) else v for k, v in kwargs.items() } return DEFAULT_FORMATTER_MAPPING["f-string"](self.template, **sanitized) # jinja2 路径启用 SandboxedEnvironment...

{替换成{{。在 Python f-string 语法里,{{是转义字符,最终渲染成字面量{,不会被当占位符解析。

和 SQL 参数化查询的哲学完全一致:数据和结构分离,不让数据改变结构的语义

Jinja2 路径启用沙箱:

from jinja2.sandbox import SandboxedEnvironment def jinja2_formatter_safe(template: str, **kwargs: Any) -> str: env = SandboxedEnvironment() # 限制属性访问,禁止危险方法 return env.from_string(template).render(**kwargs)

SandboxedEnvironment会阻断通过__class__.__mro__等 dunder 属性爬升到系统类的路径,大幅收窄 SSTI 的可利用面。

五、你的代码要怎么改:四个可直接执行的步骤

步骤一:马上升级

pip install --upgrade langchain-core # 目标:>= 0.3.84(v1.x 用户升到 >= 1.2.28) # 验证版本 python3 -c "import langchain_core; print(langchain_core.__version__)"

步骤二:全局搜索高风险用法

# 找所有用了 jinja2 格式的地方 grep -r 'template_format.*jinja2' --include="*.py" . # 找所有往 PromptTemplate.format() 传参的调用 grep -r '\.format(' --include="*.py" . | grep -v "^Binary"

重点关注:变量值来自用户请求、数据库查询结果、第三方 API 返回值的地方。

步骤三:纵深防御——额外的输入过滤层

升级之后 LangChain 自己会做 sanitize,但多一层纵深防御没坏处:

import re import logging def validate_prompt_input(text: str, max_length: int = 2000) -> str: """ 在用户输入进入 PromptTemplate 之前的额外校验层 升级到 0.3.84+ 后保留为纵深防御 """ if len(text) > max_length: raise ValueError(f"输入超长:{len(text)} > {max_length}") # 检测可疑的模板语法,记录日志供安全审计 if re.search(r'\{[^}]{0,100}\}', text): logging.warning(f"[SECURITY] 检测到可疑模板语法,来源IP可能需要关注:{text[:100]!r}") return text # 用法 user_input = validate_prompt_input(request.get("user_text", "")) result = prompt.format(rules="保持专业语气", user_text=user_input)

步骤四:模板结构绝对不能来自用户输入

# 危险:让用户选择模板字符串 user_template = request.get("template") prompt = PromptTemplate(template=user_template, ...) # ← 绝对不行 # 安全:用白名单选预定义模板 TEMPLATE_REGISTRY = { "translate": "请将以下文本翻译成英文:{text}", "summarize": "请总结以下内容,不超过200字:{text}", "qa": "基于以下上下文回答问题:\n上下文:{context}\n问题:{question}", } template_key = request.get("template_type") if template_key not in TEMPLATE_REGISTRY: raise ValueError(f"不支持的模板类型:{template_key}") prompt = PromptTemplate.from_template(TEMPLATE_REGISTRY[template_key])

六、这个漏洞揭示了一个更大的问题

从工程角度看,这个漏洞背后有个 AI 应用特有的系统性风险,比漏洞本身更值得关注。

传统 Web 应用的数据流相对简单:用户输入 → 验证 → 业务逻辑 → 数据库/响应。

AI 应用的数据流复杂得多,而且有个关键区别:中间环节的数据会被重新注入到下一轮的 Prompt 里

用户输入

向量数据库检索结果(来自外部文档,可能被攻击者预先污染)

注入面 → PromptTemplate.format()(补丁前)

LLM 推理 → Agent 决策

工具调用返回值(再次进入下一轮 Prompt)

注入面再次放大 → PromptTemplate.format()(多轮迭代)

最终输出 / 副作用(发邮件、写文件、调外部接口)

任何中间节点——工具返回值、RAG 检索结果——都可能携带恶意的模板语法。而且 Agent 的多轮迭代会把注入面放大。

这意味着 AI 应用的安全模型需要更深层地思考"什么是可信数据"。不仅用户输入不可信,外部工具的返回值同样不可信

本周 MCP Python SDK v1.27.0 发布,也包含安全修复——通过 MCP 工具返回的内容如果被不加过滤地塞进 Prompt,同样是注入面。这不是 LangChain 一家的问题,是整个 AI 工具链的系统性风险。

小结

把这次漏洞的核心逻辑串一遍:

根因str.format_map不区分"模板变量"和"变量值里的{}",用户输入可触发二次模板解析

影响:读取其他变量值;在有敏感对象传入时泄露配置数据;jinja2 模式下执行任意代码

修法:变量值进入格式化之前把{}转义成{{}};jinja2 启用 SandboxedEnvironment

原则:模板结构不能来自用户输入;所有进入 Prompt 的外部数据都视为不可信

接下来值得关注的方向:AI 应用的"输入信任边界"到底在哪里?Framework 层(LangChain 做)、工具调用层(开发者做)、LLM 的 system prompt 层(模型层做)——理想状态是三层都有,但目前缺乏统一的标准和最佳实践。这块会是 2026 年 AI 安全方向的热点。

如果这篇文章对你有帮助,欢迎转发给正在用 LangChain 做 AI 应用的同事。

http://www.jsqmd.com/news/658844/

相关文章:

  • D4: 常见误区:管理者最容易踩的 5 个坑
  • 拼多多如何批量上下架商品?拼多多一键下架所有商品操作步骤
  • 解锁NVIDIA显卡潜力:用Profile Inspector深度优化游戏性能的终极指南
  • USB运动控制 (五轴雕刻机系统)全部开源 不保留任何关键技术,PCB可直接生产,C++6.0...
  • RAG大模型落地秘籍:文档+数据库双场景问答,代码即实战!
  • ArcGIS模型构建器实战:一个模型搞定多个GDB批量转SHP(附避坑技巧)
  • 为端到端API添加Naive RAG 流程
  • 漏检率0.05%!大厂供应链3C质检实战:C#工业相机+PLC联动外观缺陷检测全流程落地
  • 深度学习特征检测终极指南:SuperPoint完整教程与实战应用
  • ESP32 OTA升级实战:从零搭建一个带版本校验和自动回滚的远程固件更新服务
  • 数据中台进入“精耕期”:五大主流数据治理平台横向测评与选型指南
  • 35岁转行AI大模型开发?零基础也能逆袭!掌握这些资源,轻松拿高薪Offer!
  • SQLJOIN连接中如何处理复杂的业务规则_子查询逻辑封装与连接
  • Montgomery模乘算法详解:从数学原理到硬件优化(含CSA加法器设计)
  • 万象视界灵坛部署教程:青云QingCloud GPU云主机CLIP优化部署
  • 新概念英语第二册04_An exciting trip
  • 选型指南:数据中台落地关键,看AI如何重塑数据治理
  • 告别同步慢与数据泄露!2026国内主流企业网盘深度横评
  • mysql权限表查询性能如何优化_MySQL系统权限缓存原理
  • 如何高效使用开源音乐API:.NET开发者的完整实战指南
  • 2025_NIPS_LLM Layers Immediately Correct Each Other
  • 2026年靠谱的钛镁合金门窗厂家推荐与选型指南 - 品牌宣传支持者
  • 【GD32H759I-EVAL开发板】LVGL内存配置实战:从概念到性能调优
  • FPGA新手必看:用Verilog让无源蜂鸣器演奏《小星星》完整教程
  • Unity3D——UGI基础知识(1)
  • 堆(优先队列)基础原理与题目说明
  • SPOOLing 技术(假脱机技术)独占设备 → 虚拟共享设备
  • 如何导入带系统变量修改的SQL_确保SUPER权限并规避只读变量报错
  • 为什么92%的团队还没用上AI设计模式生成?SITS2026未发布Demo代码+模式元模型Schema首度泄露
  • SITS2026代码补全演进全景图:3代模型对比、27项基准测试数据与2026落地风险预警