When prompts become shells——Semantic Kernel 两个 CVE 把提示词注入升级成主机 RCE:eval() 黑名单绕过 + 沙箱逃逸完整拆解(CVE-2026-25592 / CVE-2026-26030)

预计阅读时间:17 分钟

TL;DR

2026-05-07 Microsoft 安全团队公开了 AI Agent 框架安全研究系列的第一篇:在自家 Semantic Kernel(GitHub 27k+ stars)里发现两个可被提示词注入直接触发的主机级 RCE——CVE-2026-26030(In-Memory Vector Store 的 eval() 注入 + AST 黑名单绕过)和 CVE-2026-25592SessionsPythonPlugin 误暴露 DownloadFileAsync 导致容器沙箱逃逸)。两条漏洞的共性:AI 模型不是安全边界,框架对模型输出的信任才是漏洞面。修复无需改架构,升级依赖即可(Python SDK ≥ 1.39.4、.NET SDK ≥ 1.71.0)。本文拆解两个漏洞的攻击链、黑名单绕过的四个技术点、以及「模型层 + 主机层」双层防御的具体落地。

为什么这次值得关注:从「内容污染」到「代码执行」

提示词注入(Prompt Injection)在大多数讨论里还是「聊天机器人被骗」——模型说了不该说的话。但 Semantic Kernel 的两个 CVE 展示了 2026 年的真实威胁模型:

提示词注入
    │  框架把模型输出映射成工具调用(tool calling)
    ▼
工具参数被注入污染
    │  框架信任解析后的参数
    ▼
执行原语(eval() / 文件写入)
    │
    ▼
主机级 RCE

Microsoft 研究团队的原话:AI 模型本身没有问题——它只是把自然语言解析成工具 schema,行为完全符合设计。漏洞在于框架和工具如何信任被解析的数据。攻击者通过提示词注入控制工具参数,就等于拿到了一条通往 eval() 或文件系统的执行原语。

一条提示词就能在运行 Agent 的设备上启动 calc.exe——不需要浏览器漏洞、不需要恶意附件、不需要内存破坏。Agent 只是「按设计工作」:理解意图、选工具、传参数。

CVE-2026-26030:In-Memory Vector Store 的 eval() 注入

背景:酒店搜索 Agent

Microsoft 构建了一个演示用「酒店搜索」Agent:

  1. 创建 In-Memory Vector 集合存酒店数据;
  2. 暴露 search_hotels(city=...) 函数给模型(tool calling);
  3. 用户问「Find hotels in Paris」→ 模型调用 search_hotels(city="Paris")

漏洞点 1:不安全的字符串插值

Semantic Kernel 的默认过滤函数用 Python lambda 实现,并在 eval() 里执行:

# 用户输入 "Paris" → 生成的过滤表达式
new_filter = "lambda x: x.city == 'Paris'"

问题在于 kwargs[param.name]Paris)是 AI 模型可控的输入,且未消毒。这是一个经典的注入 sink:攻击者通过提示词注入让模型输出一个「特殊城市名」,闭合掉引号,追加任意 Python 逻辑:

# 恶意输入闭合引号 + 追加代码
city = "Paris'); import os; os.system('calc'); #"
# 拼出来的 lambda:
lambda x: x.city == 'Paris'); import os; os.system('calc'); #"

漏洞点 2:可绕过的 AST 黑名单

框架开发者其实预料到了 RCE 风险,实现了一个校验器:先把过滤字符串解析成 AST(抽象语法树),检查有没有危险节点,通过后才执行。

思路是对的,但动态语言里的黑名单天然脆弱。Microsoft 的 exploit prompt 构造了以下绕过,四条同时满足:

# 绕过点 具体手法
1 危险名字不在黑名单 payload 用的属性不在 ast.Name / ast.Attribute 黑名单里
2 结构检查被欺骗 整体包在合法 lambda 里,isinstance(tree.body, ast.Lambda) 通过——恶意代码只是 lambda 的函数体
3 __builtins__ 无关紧要 eval(..., {"__builtins__": {}}) 想移除内置函数,但 payload 从 tuple() 开始(tuple 不需要 builtins),沿 Python 类型系统(__class____mro____subclasses__BuiltinImporter)爬上去动态加载 os
4 ast.Subscript 没检查 黑名单只查 ast.Name/ast.Attribute,但 obj['__class__'](下标访问)产生 ast.Subscript 节点,完全绕过检查

最终 payload 以合法 lambda 形式逃过 AST 校验,在 eval() 里动态加载 os.system(),启动任意 shell 命令。

修复(四层防护)

升级 Python semantic-kernel 依赖到 ≥ 1.39.4。官方修复采用四层防护,消除把 lambda filter 变成可执行代码所需的每种逃逸原语:

  1. 过滤函数不再允许用户构造任意 Python 表达式(改为安全 DSL/预编译查询);
  2. AST 校验升级:处理 SubscriptCall、属性链等所有节点类型;
  3. 执行环境隔离:不再在 eval() 里执行用户可控字符串;
  4. 默认拒绝 + 显式允许列表。

自查是否受影响

以下条件全部满足才受影响:

  • 使用 Python 版 Semantic Kernel < 1.39.4;
  • 使用了 In-Memory Vector Store 且暴露了带参数过滤的搜索函数;
  • 搜索参数可由 AI 模型/最终用户输入控制。

CVE-2026-25592:SessionsPythonPlugin 沙箱逃逸

背景:容器边界当安全边界

Semantic Kernel 内置 SessionsPythonPlugin,让 Agent 在 Azure Container Apps 动态会话(隔离的云沙箱)里安全执行 Python。安全模型完全依赖这个边界:代码跑在隔离沙箱里,碰不到 Agent 进程所在的主机。沙箱内外传数据靠 UploadFile / DownloadFile 辅助函数(运行在主机侧)。

漏洞:一个 [KernelFunction] 属性把文件写入变成 AI 可控工具

在 .NET SDK 里,DownloadFileAsync误标[KernelFunction] 属性——这个属性把它正式注册成模型可调用的工具,附带完整参数 schema:

[KernelFunction]  // ← 误标:向 AI 模型暴露为可调用工具
public async Task DownloadFileAsync(string localFilePath, ...)
{
    await File.WriteAllBytesAsync(localFilePath, ...);  // 无路径校验
}

localFilePath 参数(决定 File.WriteAllBytes() 把数据写到主机哪个位置)现在完全由 AI 控制。没有路径校验、没有目录限制、没有消毒。攻击者不需要复杂 hypervisor 漏洞,只需要提示模型去调用它

(注:upload_file() 有反向的类似问题——接受任意本地文件路径,允许注入把主机的 SSH 密钥/凭据读出到沙箱。)

攻击链三步

Step 1: 注入指令 → 模型调用 ExecuteCode 在沙箱内生成恶意脚本
         (此时 payload 被关在沙箱里,无害)
             │
             ▼
Step 2: 注入指令 → 模型调用 DownloadFileAsync(localFilePath=主机 Startup 目录)
         (下载沙箱脚本 → 写入主机 Windows\Start Menu\Programs\Startup)
             │
             ▼
Step 3: 用户下次登录 → 脚本自动执行 → 主机完全沦陷

对应 MITRE ATLAS 技术:AML.T0051 (LLM Prompt Injection) 级联成 AML.T0016 (Obtain Capabilities)

修复

升级 .NET SDK 到 ≥ 1.71.0。核心修复:移除 [KernelFunction] 属性,让函数对 AI 模型不可见——攻击链的第一步就断了。Agent 现在只能被开发者代码显式调用。

修复版本与自查对照表

SDK 受影响版本 修复版本 自查动作
Semantic Kernel Python < 1.39.4 ≥ 1.39.4 pip show semantic-kernel 查版本
Semantic Kernel .NET < 1.71.0 ≥ 1.71.0 dotnet list package 查版本
In-Memory Vector Store 用户 所有旧版本 同上 检查是否暴露带参数过滤的搜索函数

升级不是重写:Microsoft 明确说明修复只是移除 AI 模型的自主调用能力,Agent 架构不用动。升级后回归测试重点:① 业务侧工具(你自己注册的 [KernelFunction])不受影响;② 内建插件(Vector Store 过滤、SessionsPythonPlugin)行为不变但模型不再能自主触发文件写入。

漏洞窗口期的追溯排查:如果 Agent 曾在受影响版本运行,需要回溯: 1. 界定窗口:部署受影响版本 → 升级到修复版的时间段; 2. 主机层狩猎:窗口期内是否有异常子进程、异常外连、Startup 目录出现新文件、凭据被访问的痕迹; 3. 若发现可疑活动,按主机失陷处理:轮换 Agent 可访问的凭据与 token,排查主机可达的其他系统。

Microsoft 在博客里提供了对应的 Advanced Hunting 查询模板(KQL),可扫「Semantic Kernel Agent 主机 spawn 可疑子进程」和「.NET 宿主 spawn 可疑子进程」两类模式。

常见误区表:Agent 安全防御的五个错误认知

误区 为什么错 正确做法
「系统提示词写『忽略不可信指令』就够了」 LLM 是概率模型,任何系统提示词都造不出确定性执行边界;编码注入(如盲文指令)能绕过模式匹配 指令级防御只是第一层,工具侧校验 + 主机层检测必须有
「模型输出只是文本,不会造成真实危害」 Agent 接了工具后,模型输出会被映射成工具调用——参数污染 = 执行原语 把工具参数当攻击者输入,做输入校验/白名单
「框架是微软的,肯定安全」 微软自家框架照样出两个 RCE(CVE-2026-25592/26030),官方也承认模型不是安全边界 依赖库升级 + 自己的安全检查,谁家都不豁免
「黑名单能挡住危险操作」 Python 动态性让黑名单可被绕过:obj['__class__'] 产生 ast.Subscript 节点,绕过只查 Name/Attribute 的校验 默认允许 + 白名单,而不是默认拒绝 + 黑名单
「沙箱/容器 = 绝对隔离」 沙箱边界依赖「主机侧辅助函数不被模型调用」,一个 [KernelFunction] 误标就废掉整个边界 边界必须双层:沙箱本身 + 暴露给模型的最小工具面

同类漏洞图谱:这不是孤例

CVE-2026-25592 / CVE-2026-26030 属于 2025-2026 年集中爆发的一类「框架层 Agent RCE」:

漏洞/事件 目标 本质
CVE-2025-53773 GitHub Copilot 源码注释/Issue 里的恶意指令禁掉用户确认,授予无限制 Shell
CVE-2026-25592 Semantic Kernel [KernelFunction] 误标把文件写入暴露给模型 → 沙箱逃逸
CVE-2026-26030 Semantic Kernel 模型可控参数进 eval() → AST 黑名单绕过 → RCE
Check Point 2026-02 披露 Claude Code 仓库配置文件投毒 → 命令执行
OWASP GenAI Q1 2026 多个框架 8 起重大事件仅 1 个 CVE,其余是过度授权/供应链/注入

共性是:框架把模型输出映射到工具时缺乏信任边界。微软研究系列的标题点破了一切——"When prompts become shells"。防御者视角:Agent 框架升级不能只追功能,要追安全补丁。

间接注入:不需要直接对话的攻击面

CVE-2026-26030 的演示里攻击者直接构造 prompt;但真实世界的触发路径更多是间接注入——攻击者不需要和你的 Agent 对话:

攻击者 ──网页/文档/邮件/评论里藏指令──▶ Agent 读取外部内容
                                          │
                                          ▼
                           指令进入模型上下文(被当作任务)
                                          │
                                          ▼
                           模型调用 search_hotels / DownloadFileAsync
                                          │
                                          ▼
                                   执行原语被触发

2026 年 4 月 Google Security 和 Forcepoint X-Labs 的遥测已经确认:对手开始在公开网页上投放隐藏指令,专门劫持浏览型 Agent、编码助手和企业 Copilot。这意味着即使你的 Agent 只处理内部数据,只要它碰过任何外部来源的内容,上述两个 CVE 的攻击链就有触发面。

防御落地:模型层 + 主机层双层

Microsoft 的核心建议:AI 模型不是安全边界。防御必须跨两层做关联:

模型层(意图检测)

  • 元提示词(meta-prompt)约定工具使用权限:哪些工具可自主调用、哪些需人工确认;
  • 内容安全过滤器:对工具参数做输入校验(类型、长度、路径格式);
  • 参数白名单:限制 localFilePath 等参数只能落在允许目录;
  • 对高危险工具(文件写入、命令执行、凭据访问)默认不给模型暴露,或加人工审批。

主机层(执行检测)

模型层被绕过是迟早的事(Microsoft 原话:提示词注入「不太可能被完全解决」),主机层必须兜底:

  • 端点检测:Agent 进程突然 spawn 子进程、写 Startup 目录、发起异常外连 → 告警;
  • 工具调用审计日志(防篡改):记录每次工具调用的参数和结果;
  • 最小权限:Agent 进程用非特权账号运行,文件系统写权限最小化;
  • 沙箱/容器跑 Agent:即便被注入,爆炸半径限于沙箱。

自查清单

  • [ ] 用的 Semantic Kernel 版本:Python ≥ 1.39.4 / .NET ≥ 1.71.0?
  • [ ] 所有 [KernelFunction] 暴露的工具,其参数是否被当作攻击者输入处理?
  • [ ] 有没有工具参数能到达 eval() / exec() / 文件写入 / 命令执行?
  • [ ] Agent 进程权限是否最小化(非 root、目录写权限受限)?
  • [ ] 工具调用有没有审计日志 + 异常告警?
  • [ ] 有无容器/沙箱边界,注入后爆炸半径多大?

启示:把每个工具参数当成攻击者输入

两个 CVE 的共同根因不是模型不够安全,而是框架把「解析后的工具参数」当成了可信数据。这跟 Web 安全早期把用户输入直接拼 SQL 是同一类错误——只是现在的「用户输入」是自然语言,攻击者甚至不需要直接对话,只要让 Agent 处理恶意网页/文档/评论(间接注入)就能触发。

对任何 AI Agent 开发者,最实用的一句话:所有从模型传到工具的参数,默认都是攻击者可控输入。工具侧的校验(路径、类型、范围、权限)必须像对待 Web 请求体一样严格。模型层防注入,主机层防执行,两层都有才算及格。

原始出处:Microsoft Security Blog《When prompts become shells: RCE vulnerabilities in AI agent frameworks》(2026-05-07,Microsoft Defender Security Research Team:Uri Oren / Amit Eliahu / Dor Edry);CVE-2026-25592 / CVE-2026-26030(Semantic Kernel,均已修复);CTF 演练:github.com/amiteliahu/AIAgentCTF(CVE-2026-26030)。


本文由 admin 原创,转载请注明出处。

相关推荐

评论

0
暂无评论,来发表第一条评论吧

发表评论

登录 后发表评论

发现更多