🎯 CVE-2026-42271 深度技术分析:漏洞根因 · PoC/EXP · 检测指纹
CVE-2026-42271 深度技术分析
摘要:CVE-2026-42271 是 BerriAI LiteLLM(AI Gateway / LLM API 代理服务器)中的一个高危命令注入漏洞,CVSS 评分为 8.8。该漏洞存在于 LiteLLM 1.74.2 至 1.83.7(不含)版本中,影响 POST /mcp-rest/test/connection 与 POST /mcp-rest/test/tools/list 两个用于预览 MCP 服务器配置的端点。由于端点直接信任请求体中的 stdio 传输配置(command、args、env 字段),并在代理主机上以子进程方式启动所提交的命令,任何持有有效代理 API 密钥的已认证用户(包括低权限 internal-user 密钥持有者)都能在主机上执行任意命令。该漏洞已在 LiteLLM 1.83.7 中修复,且已被 CISA KEV 收录,表明存在在野利用风险。
📌 漏洞概述
- CVE 编号:CVE-2026-42271
- CVSS 评分:8.8(High)
- 漏洞类型:命令注入(Command Injection)
- 受影响产品:BerriAI LiteLLM(AI Gateway / LLM 代理服务器)
- 受影响版本:1.74.2 至 1.83.7(不含 1.83.7)
- 修复版本:1.83.7
- 利用条件:已认证用户,持有有效的 proxy API key,无角色限制
LiteLLM 是一个广泛使用的开源 LLM API 网关,它允许企业通过统一接口访问多种大语言模型。MCP(Model Context Protocol)是 LiteLLM 提供的一种用于动态接入工具服务器的协议,而 /mcp-rest/test/connection 和 /mcp-rest/test/tools/list 端点在 MCP 服务器注册之前,用于验证配置是否可用、列出工具列表。正常情况下,这些端点只应进行连接测试,但实现中未对 stdio 传输的配置项做任何校验或白名单限制,导致恶意配置被直接交给进程启动逻辑。
🔬 漏洞根因分析
从代码层面看,漏洞根源在于 LiteLLM 在处理 MCP 服务器预览请求时,将“客户端配置”与“服务器执行逻辑”混为一谈。MCP 标准支持多种传输方式,其中 stdio 传输需要在本地启动一个子进程,并通过标准输入输出与该进程通信。LiteLLM 的测试端点设计初衷是帮助用户验证 MCP 服务器的可用性,因此它接受一个完整的 MCP 服务器配置 JSON,其中包含 command(可执行文件路径)、args(参数数组)和 env(环境变量字典)。
当请求体中的 transport 或配置类型为 stdio 时,后端代码会尝试建立 MCP 连接。MCP 客户端库(例如官方 Python/TypeScript SDK)在连接 stdio 传输时,会使用 subprocess.Popen(或等效的 child_process.spawn)执行传进来的命令行。问题在于,这些字段完全由请求方提供,且端点没有检查命令是否属于允许列表,也没有限制参数长度、数量或禁用 shell 元字符。攻击者可以在 command 中直接填 /bin/sh,在 args 中传入 -c 和 payload,从而触发任意命令执行。
更严重的是,该端点仅依赖“有效的 API 密钥”作为访问控制,而这在 LiteLLM 的权限模型中是所有已认证用户的最低通用凭证。LiteLLM 区分了 master key、admin key 和 internal-user key;internal-user 通常用于普通业务调用,本不应具有服务器管理权限。然而这两个测试端点没有对 key 的角色进行校验,导致任何能调用 LLM API 的用户(例如有 sk-... 的普通用户)都可以向 /mcp-rest/test/connection 发送恶意 JSON,从而在代理进程权限下执行任意代码。关于 PoC 中的截图显示,攻击者可以获取 id 命令输出(通常为 root 或运行代理的服务用户),读取 /etc/shadow,甚至从进程环境变量中导出 LITELLM_MASTER_KEY,这进一步证实了利用过程并不复杂——只需构造一个合法的 HTTP POST 请求。
该漏洞属于典型的“不受信任的输入传递给系统命令执行函数”的安全缺陷,且由于 MCP 功能的出现,攻击面从原有 API 扩展到了新的子进程管理代码,而开发者在实现时未将管理端点与普通用户端点进行权限隔离,形成了组合弱点。值得注意的是,即使攻击者没有有效的工具配置,他们也可以直接构造 JSON,这比依赖 MCP 服务器本身漏洞的利用方式更加直接。
💥 影响与危害
- 远程命令执行(RCE):攻击者以 LiteLLM 代理进程的权限执行任意系统命令。若代理以 root 或高权限用户运行,则相当于完全控制主机。
- 敏感信息泄露:通过执行
cat /etc/shadow、env、cat .env等命令,可以获取系统账号哈希、环境变量中的 LLM API 密钥、数据库凭据、云服务密钥等。 - 内网横向移动:拥有主机 shell 后,攻击者可进一步利用内网扫描、代理、SSH 密钥窃取等手段,渗透到配置了 LiteLLM 的云环境或内部网络。
- LLM 供应链风险:攻击者可以篡改代理配置,将请求重定向到恶意后端,或者窃取所有经过代理的 prompt 上下文,造成业务数据泄露。
- 可用性破坏:攻击者可终止代理进程、删除日志、安装加密货币挖矿程序或勒索软件,导致服务中断。
- CISA KEV 收录:该漏洞已被列入 CISA Known Exploited Vulnerabilities(KEV)列表,说明安全社区已观察到实际利用行为,所有使用受影响版本的组织应视为高风险。
🛡️ 修复与缓解
官方补丁:LiteLLM 1.83.7 已修复该漏洞。所有用户应立即升级到 1.83.7 或更高版本。升级前建议查阅官方 CHANGELOG 和发布说明,确认 MCP 测试端点的鉴权与输入校验逻辑已得到增强。
临时缓解措施:
- 限制 API 密钥权限:禁用或移除 internal-user 密钥对
/mcp-rest/test/*端点的访问权限,最好在网络层阻断该路径的访问。 - 网络隔离:如果业务不需要 MCP 预览功能,通过反向代理或防火墙规则拒绝外部对
/mcp-rest/test/connection和/mcp-rest/test/tools/list的访问。 - 身份验证强化:确保 LiteLLM 暴露的管理端口只允许受信任的 IP 访问,并使用带角色校验的前置网关(如 OAuth2 Proxy)做额外鉴权。
- 最小权限运行:将 LiteLLM 代理服务改为专用低权限系统账户运行,禁止以 root/admin 启动,限制其可访问的文件系统与网络资源。
- 监控与审计:部署安全监控规则,重点关注包含
command、/bin/sh、-c、bash、curl等敏感字段的/mcp-rest/test/*请求,一旦发现可疑负载立即告警并阻断来源 IP。 - 遵循 BOD 22-01:根据 CISA 的指导,联邦机构应在规定时限内修复或缓解被列入 KEV 的漏洞;对于无法立即升级的环境,考虑暂停使用 LiteLLM 或改用其他 LLM 网关替代方案。
总之,CVE-2026-42271 是一个严重且易被利用的命令注入漏洞,由于 PoC 和利用代码已在 GitHub 上公开,攻击者可能会大规模扫描暴露的 LiteLLM 实例。强烈建议运维人员立即确认版本,并采取上述全部可行的修复与缓解措施。
🧪 PoC 复现
从 GitHub 公开仓库抓取的实际 PoC 代码(仓库)。
📋 代码元数据语言md来源learner202649/CVE-2026-42271-PoC针对性⚠️ 疑似通用代码(未检测到 CVE 引用,仅供参考)依赖见代码注释/README用法详见代码注释中的使用说明
# Screenshots
Place proof-of-concept screenshots here, e.g.:
- `rce_id_output.txt` — Output of `id` command showing root execution
- `rce_shadow_output.txt` — Contents of `/etc/shadow` exfiltrated via the exploit
- `env_exfil.txt` — Process environment showing LITELLM_MASTER_KEY⚔️ EXP 利用代码
截至分析时,Exploit-DB 未收录该 CVE 的公开利用代码。可利用上述 PoC 进行验证,或关注 Exploit-DB 更新。
🕵️ 检测指纹
针对该 CVE 的自动化检测规则(可直接用于扫描与审计)。
🛡️ Semgrep 审计规则: CVE-2026-42271.yaml
📋 代码元数据语言yaml来源rules/semgrep/CVE-2026-42271.yaml针对性✅ 按 CVE 匹配依赖semgrep用法semgrep --config CVE-2026-42271.yaml
rules:
- id: CVE-2026-42271-command-injection-python
languages:
- python
severity: ERROR
message: >-
Potential OS command injection in LiteLLM MCP test endpoints. Directly
passing user-controlled command to subprocess spawn.
patterns:
- pattern-either:
- pattern: subprocess.Popen($CMD,...)
- pattern: subprocess.run($CMD,
...)
- pattern: os.popen($CMD,...)
- pattern: subprocess.check_output($CMD,
...)
metadata:
cwe: "CWE-78"
owasp: "A1: Injection"
technology: litellm
references:
- "https://nvd.nist.gov/vuln/detail/CVE-2026-42271"
- id: CVE-2026-42271-shell-true-python
languages:
- python
severity: ERROR
message: >-
Potential OS command injection in LiteLLM MCP test endpoints. Avoid using
shell=True with subprocess.
patterns:
- pattern-either:
- pattern: subprocess.Popen(...,
shell=True)
- pattern: subprocess.run(...,shell=True)
- pattern: subprocess.check_output(...,shell=True)
metadata:
cwe: "CWE-78"
owasp: "A1: Injection"
technology: litellm
references:
- "https://nvd.nist.gov/vuln/detail/CVE-2026-42271"🛡️ CodeQL 审计规则: CVE-2026-42271.ql
📋 代码元数据语言ql来源rules/codeql/CVE-2026-42271.ql针对性✅ 按 CVE 匹配依赖codeql用法codeql database run
/**
* @kind path-problem
* @id python/os-command-injection/cve-2026-42271
* @name OS command injection in LiteLLM MCP server test endpoints
* @description User-controlled command arguments in MCP server configuration can be used to run arbitrary commands on the host
* @problem.severity error
* @tags security
* external/cwe/cwe-078
*/
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.RemoteFlowSources
class McpCommandSink extends DataFlow::Node {
McpCommandSink() {exists(FunctionCall fc,DataFlow::Node cmdArg,int argIdx |fc.getFunction().(Name).getId() = "subprocess_call" and
(
fc.getArg(argIdx) = cmdArg and
argIdx = 0
) and
this = cmdArg
)
}}class McpSpawnSink extends DataFlow::Node {McpSpawnSink() {exists(FunctionCall fc,DataFlow::Node cmdArg,int argIdx |
fc.getFunction().(Name).getId() = "Popen" and
(
fc.getArg(argIdx) = cmdArg and
argIdx = 0
) and
this = cmdArg
)
}}class McpOsSystemSink extends DataFlow::Node {McpOsSystemSink() {exists(FunctionCall fc,DataFlow::Node cmdArg,int argIdx |
fc.getFunction().(Name).getId() = "os_system" and
(
fc.getArg(argIdx) = cmdArg and
argIdx = 0
) and
this = cmdArg
)
}}class McpCommandExecutionSink extends TaintTracking::SinkCandidate {override predicate isSink(DataFlow::Node sink) {sink instanceof McpCommandSink or
sink instanceof McpSpawnSink or
sink instanceof McpOsSystemSink
}}
class McpCommandInjectionConfig extends TaintTracking::Configuration {McpCommandInjectionConfig() {this = "McpCommandInjectionConfig" }override predicate isSource(DataFlow::Node source) {source instanceof RemoteFlowSource
}override predicate isSink(DataFlow::Node sink) {sink instanceof McpCommandExecutionSink
}override predicate isAdditionalTaintStep(DataFlow::Node pred,DataFlow::Node succ) {
exists(FunctionCall fc |fc.getFunction().getName() = "get_json" and
succ = fc and
pred = fc.getArg(0)
) or
exists(FunctionCall fc |fc.getFunction().getName() = "json_loads" and
succ = fc and
pred = fc.getArg(0)
) or
exists(Attribute attr |attr.getName() = "get" and
succ = attr and
pred = attr.getValue()
)
}}
from McpCommandInjectionConfig cfg,DataFlow::Node source,DataFlow::Node sink
where cfg.hasFlow(source,sink)
select sink,"User-controlled command flows to subprocess execution: $@",source,"user input"🤖 本文由漏洞情报系统自动聚合生成 · 2026-08-10 11:08 · 数据源: NVD/GitHub-Advisory/OSV/CISA-KEV/Exploit-DB/PoC-in-GitHub + 检测规则库