LangChain LLMMathChain 的 LLM 输出执行路径
一句话
据 NVD,LangChain through 0.0.131 的 LLMMathChain 允许 prompt injection 影响 LLM 生成的 Python 表达式,并经 Python exec 路径触发 ToLO-Exec。
公开事实与待核验
| 项 | 本页采用的读法 |
|---|---|
| 公开来源明确支持 | CVE-2023-29374、LLMMathChain、prompt injection、Python exec 执行路径、LangChain through 0.0.131。 |
| ToLO 解释 | 这是 S_LLM^{framework} 到 ToLO-Exec sink 的路径。S_LLM^{framework} 指框架包装后的 LLM 输出,不是用户直接提交的字符串。 |
| 版本状态 | NVD 给出 affected range;公开来源未在同一处闭合 release tag 与 fixed version。 |
为什么 pending | PR #1119、PR #2943、commit 5ca7ce7 展示了修复演进,但本页尚未把所有来源的版本口径做成完全一致的 release 结论。 |
怎么读这个案例
把它当成”自然语言数学问题变成可执行代码”的入门例子。用户看见的是数学问答功能;框架内部做的是让 LLM 生成可计算表达式,再交给执行环境。
ToLO 的关键就在这次转换:模型输出不再只是答案,而是被提升成程序。
这个案例非常适合作为整个 ToLO 学习的”开场” —— 因为它把 source、sink、guard 三个概念都摆在最直接的位置:
- source: LLM 输出的 Python 表达式
- sink:
exec/PythonREPL - guard: 缺失
影响组件
影响组件是 LangChain 的 LLMMathChain,即把数学问题交给 LLM 转写为可计算表达式的 chain。
NVD 给出的受影响范围是 <= 0.0.131;上游 issue #1026 与 PR #1119 均把风险定位到 llm_math 中对 LLM 输出代码的执行。
| 来源 | affected_versions | fixed_in |
|---|---|---|
| NVD | <= 0.0.131 | — |
| 上游 issue / PR | 指向 llm_math 的 Python 执行路径 | PR 链路需要与 release tag 继续核对 |
Commit 5ca7ce7 | — | 该 commit 后(PR #2943) |
| Release tag | (未直接给出) | fixed_in: unknown |
版本口径有不一致,因此本页保持 verification: pending。
ToLO 路径
| 列 | 内容 |
|---|---|
| Source | S_LLM^{framework} —— LLMMathChain 接收的 LLM 文本输出 |
| Transform | chain 从模型输出中解析代码块或表达式,送给数学计算逻辑 |
| Sink | 修复前的 Python REPL / exec 执行路径(对应 ToLO-Exec / CWE-94) |
| Guard 缺失 | 缺少与代码执行 sink 匹配的 C_SAFE^{safe-codec} 与 C_SAFE^{capability};数学表达式没有被限制在更窄的能力集合中 |
| Impact | 公开来源按 code execution / arbitrary code execution 描述;本页不扩展为可操作利用链 |
| Repair pattern | 移除通用 Python 执行路径,改用更窄的表达式求值器并收紧可访问上下文 |
这条路径展示了”看似只是数学计算”如何变成执行边界问题。只要表达式语言足够接近 Python,LLM 输出就不再只是数据,而是在决定解释器要执行什么。
攻击者通道
- 主要 C1(直接 prompt injection):用户的问题字段直接影响 LLM 输出。
- 本页不把 C2-C5 写入该 CVE 的事实结论。若某部署把网页、文档或工具返回再送入数学问题,那是部署层面的额外通道,需要另行核验。
教学骨架(简化,不可直接复现)
from langchain.chains import LLMMathChainfrom langchain_openai import OpenAI
# 修复前的 LLMMathChain 简化骨架llm = OpenAI()chain = LLMMathChain.from_llm(llm)
# 用户问题假设是一个普通数学问题。# 模型输出可能包含:# ```python# <math_expression># ```# chain 内部:# 1. 用 prompt 模板引导模型输出 Python 表达式# 2. 用 regex 从输出里提取 ```python ... ``` 块# 3. 把提取出的字符串送给 PythonREPL.run(...)# — 这一步 PythonREPL.run 底层是 exec()## 风险点不是某个具体输入,而是 LLM 输出可以越过# "数学表达式"边界,进入通用 Python 执行语义。⚠ 这只是教学骨架。不要把它作为攻击 PoC 使用。
修复方式
PR #1119 曾提出把 exec 降为 eval,但未合并。随后合并的 PR #2943 / commit 5ca7ce77 移除了 LLMMathChain 的 Python REPL 路径,改用:
numexpr.evaluate(expr, global_dict={}, local_dict={"pi": math.pi, "e": math.e})处理单行数学表达式。
公开来源未直接给出对应 release tag,因此 fixed_in 暂记为 unknown。
修复属于哪一类 C_SAFE?
主要属于 C_SAFE^{safe-codec}。这里的 C_SAFE 指能切断 source-to-sink 风险的防护集合;safe-codec 指用不会恢复任意对象或执行通用代码语义的解析/求值机制:
把”任意 Python”收窄到”数学表达式子集”。
具体机制:
numexpr.evaluate是专用数学表达式引擎,不支持 function calls、attribute access、import 等。global_dict={}+local_dict={"pi": pi, "e": e}让上下文只剩两个常量,无任何危险对象。
但不能算无条件安全:
numexpr自身有过历史 CVE(详见 CVE-2023-39631)。- 上下文如果泄露其他对象,仍可能被滥用。
因此本页不把它写成无条件 sanitizer,而是写”收窄能力 + 依赖底层引擎安全”。
为什么仍保持 pending
本页的 ToLO 路径已经足够用于教学,但版本闭合仍有待核验:
- NVD 明确给出 affected range,但没有把本页列出的 PR / commit 与一个单独 fixed tag 完整对应起来。
- PR #1119 与 PR #2943 代表不同修复尝试;教学上可比较其语义,但不能把未合并尝试写成最终修复。
numexpr后续也出现过单独 CVE,所以”改用求值器”只能写成降低风险的 repair pattern,不能写成永久安全结论。
对 ToLO 分类的启发
该案例支持 ToLO-Exec 子类:问题不只是传统代码注入 sink,而是框架把 LLM 生成的”内部计算步骤”当作可信代码。
修复方向也说明:ToLO-Exec 更适合通过收窄可执行语言和能力边界来处理,而不是仅靠普通字符串过滤。
它还提示检测规则不能只查 eval 字面调用:
PythonREPL类、helper wrapper、数学链封装都可能隐藏真实执行 sink。- 需要通过框架模型或调用图展开。
- CodeQL 需要为
langchain_experimental.utilities.python.PythonREPL这类类的run方法显式建 sink 模型。
学习者要带走什么
- 数学表达式、代码片段、查询语句都可能从”文本”变成”程序动作”。“看起来无害的功能”和 ToLO 没有矛盾。
- 把
exec换成更窄的表达式求值器是降低风险的方向,但仍要看求值器本身能力。 ToLO-Exec的重点不是用户直接提交代码,而是 LLM 输出被框架当成可信代码。
读完检查
试着回答:
- 这个案例里,source 是什么?sink 是什么?
- source:
S_LLM^{framework}(LangChainLLMChain.run()返回的字符串) - sink:
PythonREPL.run()→ 底层exec()
- source:
numexpr.evaluate(..., global_dict={}, local_dict={...})为什么只能算收窄能力,而不能等于完全安全?- 它收窄了语言(只数学表达式)和上下文(只两个常量),但仍依赖 numexpr 库本身没有可被触发的执行边界缺陷。历史上 numexpr 也有 CVE。
- 这个案例的 ToLO 通道主要是 C 几?
- C1。除非应用接 RAG / web fetch 等让外部内容影响数学问题。
公开来源
- https://nvd.nist.gov/vuln/detail/CVE-2023-29374
- https://github.com/hwchase17/langchain/issues/1026
- https://github.com/hwchase17/langchain/pull/1119
- https://github.com/langchain-ai/langchain/pull/2943
- https://github.com/langchain-ai/langchain/commit/5ca7ce77cd536991d04f476e420446a3b21d2a7b
下一步阅读
- CVE-2023-36258 LangChain PALChain:同子类(Exec),但 PAL 设计本身把执行作为正常功能。
- CVE-2023-39631 LangChain numexpr:本案修复用的
numexpr自身也有过 CVE。 - Defensive Patterns §
C_SAFE^{safe-codec}:安全解码器的工程要点。