LangChain PALChain 任意代码执行
一句话
据 NVD 与 GitHub Advisory,LangChain PALChain 在部分旧版本中把 LLM 生成的 Python 代码交给执行路径,形成 ToLO-Exec。
怎么读这个案例
PALChain 是 Program-Aided Language Models(PAL)的代表场景:让模型写一段程序来辅助推理。论文出处:Gao et al. 2022 “PAL: Program-Aided Language Models”。
对学习 ToLO 来说,它是最典型的 “功能设计本身需要执行 LLM 输出” 案例。
因此不要只把它理解成”某个地方用了 exec”。更重要的是理解:当产品功能允许模型生成代码时,安全边界必须重新设计,不能靠”模型应该生成好代码”这个假设。
PAL 和 LLMMathChain 的差别:
| LLMMathChain | PALChain | |
|---|---|---|
| 设计目的 | 计算数学题 | 多步程序推理(可以写循环、条件、变量) |
| 模型输出 | 一段表达式 | 一整段 Python 程序 |
| 修复方向 | 换求值器 | 移除任意 exec / AST 限制 / 显式确认 |
影响组件
影响组件是 LangChain 的 PALChain,相关功能是 Program-Aided Language Models 的数学/推理链。
| 来源 | affected_versions | fixed_in |
|---|---|---|
| NVD | before 0.0.236 | 0.0.236 |
| GitHub Advisory | < 0.0.247 | 0.0.247 |
两者版本口径不一致,因此本页保持 verification: pending。
ToLO 路径
| 列 | 内容 |
|---|---|
| Source | S_LLM^framework — PALChain 从 LLMChain 取得的生成代码文本 |
| Transform | 链将用户问题送入模型,把模型输出作为 Python 代码片段传给执行工具 |
| Sink | PythonREPL.run(...) 及其底层 exec 路径(ToLO-Exec / CWE-94) |
| Guard 缺失 | 缺少与代码执行匹配的 C_SAFE^allowlist(可执行语法白名单) / C_SAFE^capability(执行隔离) |
这条路径的关键不是”用户输入里出现了 Python 代码”,而是 PAL 设计本身允许 LLM 生成程序片段并交给执行环境。也就是说,危险来自框架功能边界:自然语言推理结果被提升为可执行代码。
教学骨架(简化)
# PAL 简化骨架question = "Alice 有 3 个苹果,Bob 给了她 5 个,她吃了 2 个,还有几个?"
prompt = """请把下面的数学问题写成 Python 程序求解。
问题: {question}
输出格式:```python# 解题代码answer = ..."""
llm_output = llm.invoke(prompt.format(question=question))
模型可能输出:
```python
alice = 3
alice += 5
alice -= 2
answer = alice
```
从输出提取代码块
code = extract_code_block(llm_output)
!!! 修复前:直接执行
exec(code) # ← ToLO-Exec print(answer)
如果攻击者通过 prompt 诱导模型输出 `import os; os.system('id')`,**这段代码会原样执行**。
## 修复方式
据 PR `#6003` 与 commit `e294ba4`,上游做了三件事:
### 1. 引入 `PALValidation` —— AST 检查
在执行前用 Python `ast` 模块**解析生成的代码**,**默认禁止**:
- `import` / `from ... import ...`(无法引入任意模块)- 调用 builtins 中危险函数(`open`、`exec`、`eval`、`compile`、`__import__` 等)- 文件 / 系统访问相关 API
伪代码示意:
```pythonimport ast
ALLOWED_NODE_TYPES = {ast.Module, ast.Assign, ast.Name, ast.Num, ast.BinOp, ...}FORBIDDEN_NAMES = {"open", "exec", "eval", "__import__", "compile", "globals", "locals"}
def validate(code: str) -> bool: tree = ast.parse(code) for node in ast.walk(tree): if type(node) not in ALLOWED_NODE_TYPES: raise ValueError(f"forbidden node: {type(node).__name__}") if isinstance(node, ast.Name) and node.id in FORBIDDEN_NAMES: raise ValueError(f"forbidden name: {node.id}") return True2. 给 PythonREPL.run 增加 timeout
防 DoS,但不防代码执行本身。
3. 后续 allow_dangerous_code 标志
更后续的版本中,LangChain 把 PALChain 默认设为 allow_dangerous_code=False,要求调用方显式启用,等价于一个 explicit-approval gate。
修复属于哪一类 C_SAFE?
C_SAFE^allowlist:AST 节点 / 名字白名单 — 主要 sanitizer。C_SAFE^capability:allow_dangerous_codeflag — explicit approval。- 残余:即使 AST 校验,仍要看上下文里的全局变量、
__class__/__subclasses__等元编程绕过可能。
⚠ Python AST 白名单历史上多次被绕过(().__class__.__mro__[1].__subclasses__() 是经典 SSTI / sandbox 逃逸 payload)。AST 白名单需要配合执行隔离(进程沙箱、syscall 限制)才稳。
对 ToLO 分类的启发
该案例支持 ToLO-Exec 子类:sink 是传统 CWE-94 代码执行,但 source 是框架内部的 LLM 输出。
它不需要新增 sink 类,但提示 PAL / code-interpreter 类功能必须有明确执行能力边界。
它也说明 “功能是有意设计的”并不自动代表安全。PAL 的目标本来就是让模型生成可执行推理程序;ToLO 关心的是这个设计是否给了攻击者影响执行内容的路径,以及执行前是否有独立边界。
类似设计还有:OpenAI Code Interpreter、Anthropic Computer Use、Claude Code、SmolAgents、AutoGPT 等。所有”让 LLM 写代码并执行”的产品都属于 ToLO-Exec 高危区。
学习者要带走什么
ToLO-Exec常出现在高级功能中,不一定是开发者”误用” API。PAL、code-interpreter、agent 自动化都是有意设计执行 LLM 代码。- AST 检查属于尝试收窄语言能力,但仍要看是否覆盖危险语义。Python 的元编程(
__class__、__bases__、__subclasses__)历史上多次绕 sandbox。 - timeout 能降低资源滥用风险,但不能单独解决任意代码执行风险。
allow_dangerous_code=False是 explicit approval 模式 capability,把责任明确转给调用方 —— 但调用方常常不读 doc 直接=True。
读完检查
如果一个框架说”我们只执行模型生成的数学辅助代码”,你会检查哪些边界?至少包括:
- 允许的语法(只算术表达式?支持赋值?循环?)
- 允许的 import(默认应禁止)
- 可访问的变量(global / local 是否清空)
- 运行权限(同进程? subprocess? 容器?)
- 文件 / 网络访问(syscall 限制?)
- 超时(防资源滥用)
- 审计(是否记录所有 exec 的代码?)
至少这 7 条都做了,才算工程可接受的 ToLO-Exec 防御。
公开来源
- https://nvd.nist.gov/vuln/detail/CVE-2023-36258
- https://github.com/hwchase17/langchain/issues/5872
- https://github.com/advisories/GHSA-2qmj-7962-cjq8
- https://github.com/langchain-ai/langchain/pull/6003
- https://github.com/langchain-ai/langchain/commit/e294ba475a355feb95003ed8f1a2b99942509a9e
下一步阅读
- CVE-2023-29374 LLMMathChain:较简单的 Exec 案例,用收窄求值器修复。
- CVE-2024-5826 Vanna AI:同子类(Exec via Plotly 代码),展示 ToLO-Exec 在数据分析 / BI 场景的形态。
- Defensive Patterns §
C_SAFE^capability:capability gate + sandbox 的工程实现。