InertFluid/sk-cve-2026-26030-lab
GitHub: InertFluid/sk-cve-2026-26030-lab
一个网络隔离的 Docker 实验环境,用于复现 Semantic Kernel 内存向量存储过滤器中 eval() 沙箱绕过导致的远程代码执行漏洞(CVE-2026-26030)并对比修复版本。
Stars: 0 | Forks: 0
# CVE-2026-26030 — Semantic Kernel 过滤器 `eval()` RCE(实验环境)
一个独立且网络隔离的 Docker 实验环境,用于复现 **CVE-2026-26030**:
通过 Microsoft Semantic Kernel(Python,`< 1.39.4`)的内存向量存储搜索
过滤器引发的、可被 prompt 注入的远程代码执行(RCE)。
## 运行
```
./run.sh # builds 1.39.3 (vulnerable) and 1.39.4 (patched), runs both
```
存在漏洞的输出以 `RCE CONFIRMED` 结尾;已修复的版本会拒绝相同的
payload,并提示 `'__subclasses__' ... is not allowed`。
## 漏洞详情
一个 Agent 暴露了一个由 `InMemoryCollection` 支持的搜索工具。LLM 从对话中生成一个
**过滤表达式字符串**(`lambda x: x.city == 'Paris'`)。
该字符串会受到攻击者的影响——通过用户 prompt,或通过检索到的/工具内容中注入的
文本——并进入 `_parse_and_validate_filter`,
该函数对其进行 `compile()` 和 `eval()` 操作(`connectors/in_memory.py:383`):
```
code = compile(tree, filename="", mode="eval")
func = eval(code, {"__builtins__": {}}, {}) # nosec
```
`__builtins__` 被清空,并且首先应用了 AST 白名单——因此这是一个
**沙箱绕过**,而不是缺少防护。两个漏洞使其可被绕过:
1. **`ast.Attribute` 的访问不受限制**——没有 dunder 黑名单,因此
允许使用 `().__class__.__base__.__subclasses__` 进行 dunder 遍历。
2. **`ast.Call` 的名称检查仅当 `func` 为 `Name` 或
`Attribute` 时才会执行。** 当 `func` 是一个 `Subscript`(这*属于*白名单范围)时,
`func_name` 保持为 `None`,从而完全跳过了允许调用的函数检查。
因此,将任何可调用对象包装为 `[obj.method][0](args)` 即可调用任何内容。链式调用如下:
```
object.__subclasses__()[i] -> BuiltinImporter.load_module('os') -> os.system(cmd)
```
## Payload
```
lambda x: [[[().__class__.__base__.__subclasses__][0]()[107].load_module][0]('os').system][0]('touch /tmp/pwned_by_filter')
```
每次调用的 `func` 都是一个 `Subscript`;每一个遍历步骤都是纯粹的属性
访问。索引(`107`)是 `BuiltinImporter` 在此镜像的
`object.__subclasses__()` 列表中的位置——`exploit.py` 会在运行时自动计算它。
## 修复方案 (1.39.4)
该补丁在白名单的基础上增加了一个**危险属性黑名单**,因此
dunder 遍历会在 `eval` 之前被拒绝:
```
Access to attribute '__subclasses__' is not allowed in filter expressions.
This attribute could be used to escape the filter sandbox.
```
## 文件
| 文件 | 用途 |
|------|---------|
| `Dockerfile` | 指定 `semantic-kernel` 版本(`--build-arg SK_VERSION=`),使用非 root 用户 |
| `exploit.py` | 端到端演示:真实 collection + 搜索过滤器 -> RCE |
| `find_sink.py` | 在已安装的包中定位 `eval`/`compile` 的接收端 |
| `probe.py` | 仅通过最小化验证器确认绕过 |
| `run.sh` | 并排构建 + 运行易受攻击的和已修复的版本 |
## 博客切入点
关于 Agent 安全性论点最清晰的表述:“数据”与“指令”之间
没有边界。模型根据用户的酒店搜索生成的过滤器最终变成了
`os.system`。沙箱确实存在——包含白名单和被清空的
`__builtins__`——但依然被属性遍历 + 下标调用的组合绕过了。在博客中值得强调的缓解措施层级:根本不要对模型
输出进行 `eval`;如果必须这样做,请基于*封闭*的语法进行限制,而不是基于具有开放属性访问权限的节点白名单;并且隔离执行 worker(seccomp / 无网络访问 /
无特权),这样即便发生代码执行也不会导致全盘皆输。
标签:AI安全, Chat Copilot, Docker实验环境, Python, 安全漏洞复现, 无后门, 沙箱逃逸, 编程工具, 请求拦截, 远程代码执行, 逆向工具