trust_remote_code=False 并非信任边界:vLLM 反复出现的模型加载 RCE
CVE-2026-27893(2026 年 3 月 27 日披露)是 vLLM 第三次 trust_remote_code 绕过。两个模型文件将 trust_remote_code=True 写死,静默覆盖运维人员的设置,使恶意模型仓库得以实现 RCE。
摘要 在 vLLM 中,
--trust-remote-code=False本应阻止模型仓库在推理主机上执行任意 Python 代码。CVE-2026-27893 于 2026 年 3 月 27 日披露(CVSS 8.8),这是该边界第三次被绕过——这次是因为两个模型文件将trust_remote_code=True写死。受影响版本为 0.10.1 至 0.17.x;修复见于 0.18.0。教训不在于某个孤立漏洞,而在于一种模式:逐文件的「自行选择信任」并不是真正的信任边界。
这是什么?
CVE-2026-27893 是 vLLM 中的一处保护机制失效(CWE-693)。vLLM 是支撑大量生产级 LLM 部署的推理与服务引擎。运维人员可以传入 --trust-remote-code=False 以拒绝执行模型仓库内附带的自定义 Python 代码。发布于 2026 年 3 月 27 日 的 GitHub 安全公告显示,有两个模型实现文件忽略了该设置,向 Hugging Face Transformers 传入了字面量 trust_remote_code=True——因此远程代码仍会被执行。
值得报道的不是这一个孤立的 CVE,而是它的「家族史」。公告本身指出了两个前身:CVE-2025-66448(2025 年 12 月 1 日,通过 auto_map 的配置加载路径)以及 CVE-2026-22807(启动时更广的 auto_map 路径)。每一个都被修复过;而每一次,同一条信任边界又通过另一条代码路径被攻破。CVE-2026-27893 是这一系列中的第三个。
工作原理
运维人员的选择确实在 vLLM 的配置层级中以 self.config.model_config.trust_remote_code 的形式正确传递。但两个有漏洞的调用点根本没有读取它。根据公告,问题代码为:
# vllm/model_executor/models/nemotron_vl.py(加载视觉编码器)
AutoModel.from_config(config, trust_remote_code=True)
# vllm/model_executor/models/kimi_k25.py(加载图像处理器)
cached_get_image_processor(model_name, trust_remote_code=True)
由于字面量 True 覆盖了全局设置,Hugging Face Transformers 会在模型加载时从被引用的仓库下载并执行 Python,并以 vLLM 进程的权限运行。触发路径为:攻击者发布一个针对 Nemotron-VL 或 Kimi-K25 架构的模型仓库;运维人员加载它——以为 --trust-remote-code=False 提供了保护;vLLM 分发到这两个文件之一;写死的 True 占了上风;仓库中的代码被执行。该绕过是静默的——没有任何警告或日志条目提示运维人员的设置已被覆盖。CVSS 评分为 8.8(AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H):可经网络访问、无需攻击者权限,但运维人员必须主动发起加载(UI:R)。
为何重要
反复出现才是关键。vLLM 将各模型特定的行为委托给 model_executor/models/ 下的独立文件,每个文件都必须独立地遵守全局的 trust_remote_code 标志。没有任何中央关卡能阻止某个文件把 True 写死。结果是:每新增一个模型实现,都是再次引入同一漏洞类别的机会——这正是三次发生的情形,分别经由 config.py、启动时的 auto_map 路径,以及如今的两个模型文件。
对防御方而言,实际危险是虚假的安全感。把 --trust-remote-code=False 当作控制手段的团队,可能正在通过受影响路径加载模型,却毫无迹象表明该控制已失效。教训也超出 vLLM 本身:任何把安全关键设置的执行分散到众多独立文件、缺乏集中仲裁的框架,结构上都易受此类失效影响。披露时尚无公开的概念验证,也无野外利用证据,但受影响版本跨越了一整年的发布(0.10.1 至 0.17.x)。
防御措施
- 升级到 vLLM 0.18.0 或更高版本。 PR #36192 的修复在两个调用点将写死的
True替换为self.config.model_config.trust_remote_code。用pip show vllm检查版本。 - 不要把
trust_remote_code=False当作唯一边界。 在出站网络受限的最小化容器中运行推理,将服务层与敏感数据存储隔离,并做网络分段以限制进程被攻陷后的横向移动。 - 校验模型来源。 将加载限定于可信、已签名的发布者;在加载前对模型工件做校验和或签名,而非依赖某个运行时标志——尤其针对 Nemotron-VL 与 Kimi-K25 架构的模型。
- 扫描你自己的构建。 由于该类别反复出现,请在任何自定义或分叉的 vLLM 中,对
model_executor/models/*.py检索trust_remote_code=True字面量(以及未传递配置的from_pretrained/from_config调用)。将该检查接入 CI,以防未来的模型文件再次引入它。 - 监控静默绕过。 在模型已预缓存的环境中,加载期间从
huggingface.co出站下载.py,或在 vLLM worker 下出现意外的子进程,都是有价值的狩猎信号,表明本不该运行的远程代码被执行了。
状态
| 项目 | 参考 | 日期 | 备注 |
|---|---|---|---|
| CVE-2026-27893 公告 | GitHub (GHSA-7972-pg2x-xr59) | 2026-03-27 | 写死 trust_remote_code=True,CVSS 8.8,CWE-693 |
| 受影响版本 | vLLM | 0.10.1 → 0.17.x | Nemotron-VL 与 Kimi-K25 加载路径 |
| 修复版本 | vLLM 0.18.0 | — | 修复 PR #36192 |
| CVE-2025-66448 | GitHub (GHSA-8fr4-5q9j-m8gm) | 2025-12-01 | 首次绕过,配置路径中的 auto_map |
| CVE-2026-22807 | GitHub 公告 | 2026 | 第二次绕过,启动时更广的 auto_map 路径 |
正确的视角不是「修补一个 CVE」,而是:vLLM 中的 trust_remote_code 已经连续三次被证明是一条会漏的边界;任何把它当作硬性控制来依赖的服务栈,都应加上不依赖于「某个逐文件标志被正确设置」的隔离与来源校验。