CVE-2026-53633 Overview
CVE-2026-53633 is a critical remote code execution vulnerability in Vitest, a testing framework powered by Vite. The flaw affects Vitest Browser Mode versions 3.0.0 through 3.2.4, 4.0.0 through 4.1.7, and 5.0.0-beta.1 through 5.0.0-beta.3. Vitest exposed a cdp() API that forwarded raw Chrome DevTools Protocol (CDP) methods to clients without enforcing allowWrite or allowExec gating. A remote attacker who can reach the exposed browser API can invoke CDP methods such as Page.setDownloadBehavior and Runtime.evaluate to overwrite vite.config.ts and execute arbitrary Node.js code on the developer host or CI runner. The issue is fixed in 3.2.5, 4.1.8, and 5.0.0-beta.4.
Critical Impact
Remote attackers can achieve arbitrary code execution on developer machines and CI runners by abusing an ungated Chrome DevTools Protocol interface.
Affected Products
- Vitest 3.0.0 through 3.2.4 (Browser Mode)
- Vitest 4.0.0 through 4.1.7 (Browser Mode)
- Vitest 5.0.0-beta.1 through 5.0.0-beta.3 (Browser Mode)
Discovery Timeline
- 2026-07-14 - CVE-2026-53633 published to the National Vulnerability Database (NVD)
- 2026-07-16 - Last updated in NVD database
Technical Details for CVE-2026-53633
Vulnerability Analysis
Vitest Browser Mode runs tests inside a real browser and exposes an internal cdp() API so test code can drive the browser through the Chrome DevTools Protocol. The vulnerable implementation forwarded every CDP method the browser supports without checking whether the calling context had allowWrite or allowExec privileges. This design flaw maps to CWE-749: Exposed Dangerous Method or Function. Because the browser API surface is reachable over the network in a typical Vitest development configuration, any client that can connect to the Vitest server inherits full CDP capabilities against the driven browser.
Root Cause
The Playwright provider inside packages/browser-playwright/src/playwright.ts returned a thin wrapper that proxied send, on, off, and once directly onto the underlying CDPSession. There was no permission check between the client-facing cdp() handler and the raw session. Coverage functionality also depended on unrestricted CDP access, which meant hardening the API required extracting privileged operations such as Profiler.enable and Profiler.startPreciseCoverage into dedicated server-side commands.
Attack Vector
An attacker who can reach the exposed browser API metadata calls cdp().send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath: '<project root>' }) to redirect browser downloads into the project workspace. The attacker then triggers a download that overwrites vite.config.ts with attacker-controlled JavaScript. When Vitest reloads its configuration, Node.js evaluates the malicious config and executes arbitrary code with the developer's privileges. Runtime.evaluate provides an alternative path to execute code inside the driven page and pivot into Node.js contexts.
// Patch: packages/browser-playwright/src/playwright.ts
// The wrapper that forwarded arbitrary CDP methods was replaced so
// coverage-only operations run through gated server commands instead.
const page = this.getPage(sessionid)
const cdp = await page.context().newCDPSession(page)
return {
- send(method, params) {
- return cdp.send(method as any, params)
- },
- on(event, listener) {
- return cdp.on(event as any, listener)
- },
- off(event, listener) {
- return cdp.off(event as any, listener)
- },
- once(event, listener) {
- return cdp.once(event as any, listener)
- },
- }
+ send: cdp.send.bind(cdp),
+ on: cdp.on.bind(cdp),
+ off: cdp.off.bind(cdp),
+ once: cdp.once.bind(cdp),
+ } as any
Source: GitHub Commit 63e3b2e
// Patch: packages/browser/src/node/commands/coverage.ts
// Coverage operations move to server-side commands so the client no
// longer needs open CDP access.
import type { BrowserCommand } from 'vitest/node'
import type { BrowserServerCDPHandler } from '../cdp'
export const _startV8Coverage: BrowserCommand<[]> = async (context) => {
const session: BrowserServerCDPHandler = await context.__ensureCDPHandler()
await session.send('Profiler.enable')
await session.send('Profiler.startPreciseCoverage', {
callCount: true,
detailed: true,
})
}
export const _takeV8Coverage: BrowserCommand<[]> = async (context) => {
const session: BrowserServerCDPHandler = await context.__ensureCDPHandler()
return session.send('Profiler.takePreciseCoverage')
}
Source: GitHub Commit 385a1ae
Detection Methods for CVE-2026-53633
Indicators of Compromise
- Unexpected modifications to vite.config.ts, vitest.config.ts, or other project configuration files during or immediately after test runs.
- Browser downloads written directly into the project workspace instead of the user's downloads directory.
- Outbound network connections from node processes spawned by Vitest to unfamiliar hosts.
- New or modified files under the project root with recent timestamps that do not match a developer commit.
Detection Strategies
- Inventory package.json and lockfiles across repositories and CI images for vulnerable Vitest versions below 3.2.5, 4.1.8, or 5.0.0-beta.4.
- Enable file integrity monitoring on Vite and Vitest configuration files inside developer workstations and CI build agents.
- Alert on child processes of node or vitest that spawn shells, package managers, or credential-access binaries.
Monitoring Recommendations
- Log all inbound connections to the Vitest browser server port and restrict them to loopback in developer environments.
- Capture process creation telemetry from CI runners to correlate Vitest execution with any anomalous script or binary launches.
- Review CI job artifacts for unexpected changes to source-controlled configuration files before promoting builds.
How to Mitigate CVE-2026-53633
Immediate Actions Required
- Upgrade Vitest to 3.2.5, 4.1.8, or 5.0.0-beta.4 in every repository, developer workstation, and CI image.
- Audit vite.config.ts and related configuration files for unauthorized modifications since the affected versions were installed.
- Rotate any secrets, tokens, or SSH keys accessible from developer or CI environments that ran vulnerable Vitest versions with network-exposed Browser Mode.
Patch Information
The Vitest maintainers released fixes in v3.2.5, v4.1.8, and v5.0.0-beta.4. The patches disable the client-facing cdp API when allowWrite or allowExec is false and move coverage collection to server-side commands. See GHSA-g8mr-85jm-7xhm and pull requests #10444, #10450, and #10456 for full details.
Workarounds
- Bind the Vitest browser server to 127.0.0.1 and block external access with host or network firewall rules until patches are applied.
- Do not run Vitest Browser Mode with allowWrite: true or allowExec: true in shared, remote, or CI environments.
- Disable Vitest Browser Mode entirely on unpatched hosts and run browser-driven tests only in ephemeral, isolated containers.
# Upgrade Vitest to a patched release
npm install --save-dev vitest@3.2.5
# or
npm install --save-dev vitest@4.1.8
# Verify the installed version
npx vitest --version
# In vitest.config.ts, ensure the browser API is not exposed externally
# and that write/exec permissions remain disabled:
# browser: {
# enabled: true,
# api: { host: '127.0.0.1' },
# // allowWrite and allowExec should stay false (default)
# }
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

