Announcement

👇Official Account👇

Welcome to join the group & private message

Article first/tail QR code

Skip to content

CVE-2026-73653 Vitest Browser Mode 深度拆解:provider commands 绕过 allowWrite 的文件读写漏洞

导语

2026 年 9 月 9 日,GitHub Security Advisory 发布了一个 CVSS 9.4 分的 Critical 级漏洞:CVE-2026-73653(GHSA-p63j-vcc4-9vmv),影响 Vitest 的浏览器模式组件 @vitest/browser

漏洞核心:Vitest Browser Mode 的 6 个内置 provider commands(如 uploadtakeScreenshotscreenshotMatcherstopChunkTracedeleteTracingannotateTraces未正确检查 allowWrite 权限门,攻击者通过恶意测试用例中的路径穿越操作,可以绕过 allowWrite 限制,在目标机器上实现任意文件读取、写入和删除——直接威胁到使用 Vitest Browser Mode 的 CI/CD 流水线和开发者的本机环境。

本文从 Vitest Browser Mode 架构、provider commands 权限模型、漏洞根因、攻击链构建到完整修复时间线,做系统性深度拆解。

背景:Vitest Browser Mode 是什么

Vitest 与浏览器测试

Vitest 是 2024-2026 年最流行的 JavaScript/TypeScript 测试框架之一,凭借与 Vite 的深度集成、兼容 Jest API 以及极速执行能力,成为 React、Vue、Svelte 等现代前端框架的默认测试工具。

Vitest Browser Mode@vitest/browser)是 Vitest 的浏览器内测试组件。它允许开发者在真实浏览器环境中运行测试,覆盖 DOM 交互、CSS 渲染、网络请求等仅在浏览器中可复现的场景——远超 jsdom/happy-dom 等模拟环境的能力。

传统 Vitest 单元测试                    Vitest Browser Mode
┌──────────────┐                    ┌──────────────┐
│  Node.js     │                    │  浏览器环境   │
│  happy-dom   │ ← 模拟 DOM          │  Chrome/Edge  │ ← 真实 DOM
│  无网络请求   │                    │  真实网络栈   │
│  无 CSS 渲染  │                    │  CSS 渲染     │
└──────────────┘                    └──────────────┘
        │                                    │
        └── 单元测试覆盖率高                  └── 集成测试覆盖率高
            但无法测试真实浏览器行为            但暴露真实浏览器攻击面

Provider Commands 架构

Browser Mode 的核心设计采用 Provider Architecture

  • 测试在浏览器端执行(页面上下文)
  • 通过 Provider Commands 与 Node.js 主进程通信
  • Provider Commands 是内部 RPC 机制,允许浏览器端触发 Node.js 端操作(如文件读写、截图、追踪)
┌─────────────────────────────┐      ┌──────────────────────────────┐
│  浏览器(测试运行上下文)      │      │  Node.js Provider 进程        │
│                             │      │                              │
│  test.run()                 │      │  provider.execute()           │
│       │                     │      │       │                      │
│       ▼                     │      │       ▼                      │
│  provider commands 调用     │──────→│  检查 allowWrite → 执行操作   │
│  (upload/screenshot/...)  │ RPC  │  (写入文件/截图/删除追踪)    │
└─────────────────────────────┘      └──────────────────────────────┘

这 6 个内置 provider commands 本质上是 Node.js 侧的特权操作——它们拥有文件系统访问权限,理论上应在 allowWrite 白名单控制下运行。

漏洞根因:权限检查缺失

CVE-2026-73653 的技术本质

漏洞报告者(manus-use,2026-07-08)发现,@vitest/browser 的 provider commands 存在 系统性权限检查遗漏

6 个内置 provider commands 中,部分命令未在执行前检查调用者是否拥有 allowWrite 权限

Provider Command功能描述实际权限漏洞行为
upload上传文件到浏览器端文件可读取目标机器任意文件
takeScreenshot截取当前页面截图文件可写入目标机器任意路径
screenshotMatcher截取匹配元素截图文件可写入目标机器任意路径
stopChunkTrace停止追踪分块文件可写入目标机器任意路径
deleteTracing删除追踪文件文件可删除目标机器任意文件
annotateTraces标注追踪信息文件可读取追踪目录任意文件(信息泄露)

漏洞根因:Vitest 的权限模型假设 provider commands 只会被可信的测试代码调用。但当测试用例中包含恶意代码(例如开源依赖被供应链投毒、CI/CD 中运行不受信任的 PR 测试),攻击者可以直接构造特殊路径,让 provider commands 越过 allowWrite 白名单执行任意文件操作。

CWE 分类

该漏洞涉及三个 CWE:

  • CWE-22: Path Traversal(路径穿越)——攻击者通过 ../ 或绝对路径穿越 allowWrite 限制的目录范围
  • CWE-552: Files or Directories Accessible to External Parties(权限配置不当)——provider commands 向不应访问的外部路径开放了文件操作权限
  • CWE-862: Missing Authorization(授权缺失)——未检查调用者是否拥有执行特定操作的权限

攻击面分析

攻击向量取决于测试用例的来源:

场景一:恶意 PR 测试(供应链攻击)

攻击者提 PR → CI/CD 自动触发 vitest --browser
    → 恶意测试用例中调用 provider command
    → provider 未检查 allowWrite → 写入 SSH key / 环境变量到公开目录
    → 攻击者读取泄露的凭证

场景二:恶意 npm 包(测试框架生态投毒)

开发者安装被投毒的测试工具库(如 vitest-plugin-xxx)
    → 插件在 vitest.config 中注册自定义 provider
    → 测试运行时恶意 provider 触发文件操作
    → 由于 provider command 层面无权限检查,直接越权

场景三:本地开发环境

开发者在本地执行 git clone 并运行测试
    → 恶意 vitest.config 引导执行 malicious test
    → provider commands 写入 ~/.ssh/id_rsa 到 /tmp/.leaked
    → 开发者机器被入侵

影响范围与修复

受影响版本

包名受影响版本修复版本
@vitest/browser≤ 4.1.94.1.10
@vitest/browser≤ 3.2.63.2.7
@vitest/browser≤ 5.0.0-beta.55.0.0-beta.6

修复方案

Vitest 团队在修复版本中为所有 6 个内置 provider commands 增加了 权限前置检查:在执行任何文件系统操作前,验证当前请求路径是否落在 allowWrite 白名单目录内。未通过检查的请求将被拒绝并抛出权限错误。

立即升级

bash
# npm
npm install @vitest/browser@latest

# yarn
yarn add @vitest/browser@latest

# pnpm
pnpm add @vitest/browser@latest

短期缓解(无法立即升级时)

vitest.config 中显式禁用不需要的 provider commands,或通过自定义 provider 封装,添加路径检查中间件:

typescript
// vitest.config.ts - 短期缓解方案
import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    browser: {
      // 仅允许特定目录的写操作
      allowWrite: ['/tmp/vitest-screenshots/', '/tmp/vitest-traces/'],
    },
  },
})

与同类型漏洞的对比

CVE-2026-73653 本质上是权限模型完整性漏洞(Privilege Model Integrity),与以下漏洞属于同类:

漏洞本质后果
CVE-2026-73653(Vitest)Provider commands 未检查 allowWrite测试工具链任意文件读写
CVE-2026-50548(Cursor)AI Agent 工具链路径穿越IDE 沙箱逃逸
CVE-2026-48710(Starlette/FastAPI)Host header 路径注入认证绕过
CVE-2026-61539(Xinference)eval() 注入 → RCEAI 平台接管

共同特征:应用层授权逻辑在底层系统调用时未做校验——应用假设调用者可信,但系统层面缺乏最小权限原则。

编码层面的修复原理

修复前代码(概念还原)

typescript
// provider commands 执行入口(简化)
async function executeProviderCommand(command, params) {
  // ❌ 修复前:未检查 params.path 是否在 allowWrite 白名单内
  switch (command) {
    case 'upload':
      return await fs.readFile(params.path)    // 任意读
    case 'takeScreenshot':
    case 'screenshotMatcher':
    case 'stopChunkTrace':
      return await fs.writeFile(params.path, params.data)  // 任意写
    case 'deleteTracing':
      return await fs.unlink(params.path)       // 任意删
    case 'annotateTraces':
      return await fs.readFile(params.path)     // 任意读
  }
}

修复后代码(概念还原)

typescript
// 修复后的权限检查
function isPathAllowed(targetPath: string, allowedPaths: string[]): boolean {
  const resolved = path.resolve(targetPath)
  return allowedPaths.some(
    allowed => resolved.startsWith(path.resolve(allowed))
  )
}

async function executeProviderCommand(command, params, allowWrite) {
  const needsWrite = ['takeScreenshot', 'screenshotMatcher', 'stopChunkTrace']
  const needsRead  = ['upload', 'annotateTraces']
  const needsDelete = ['deleteTracing']

  if (needsWrite.includes(command) || needsDelete.includes(command)) {
    if (!isPathAllowed(params.path, allowWrite)) {
      throw new Error(`Permission denied: ${params.path} is not in allowWrite`)
    }
  }
  if (needsRead.includes(command)) {
    if (!isPathAllowed(params.path, allowWrite)) {
      throw new Error(`Permission denied: ${params.path} is not in allowWrite`)
    }
  }

  // ... 执行实际操作
}

Timeline

日期事件
2026-07-08漏洞报告者(manus-use)提交安全报告至 Vitest 团队
2026-07-08GitHub Security Advisory(GHSA-p63j-vcc4-9vmv)发布
2026-09-09漏洞详情公开(TheHackerWire 报道)
修复版本4.1.10 / 3.2.7 / 5.0.0-beta.6

从报告到公开披露约 63 天,属于负责任披露流程。

防御建议

  1. 立即升级 @vitest/browser 至修复版本(4.1.10 / 3.2.7 / 5.0.0-beta.6)
  2. CI/CD 隔离:在隔离容器/沙箱中运行 vitest --browser,即使漏洞被利用,损失也被限制在容器内
  3. 审查测试依赖:定期审计 vitest.config 中注册的自定义 provider 和插件
  4. 最小权限原则allowWrite 白名单应尽可能窄——仅包含测试明确需要的输出目录
  5. 监控异常文件操作:在 CI/CD 中监控 /tmp~/.ssh、环境变量文件等敏感位置的异常写入

参考链接

  1. GitHub Advisory: GHSA-p63j-vcc4-9vmv
  2. CVE-2026-73653 详情
  3. Vitest 官方文档 - Browser Mode
  4. TheHackerWire: Vitest Browser Mode Path Traversal
  5. TheHackerNews: CVE-2026-73653

上次更新于: