CVE-2026-47428 - Vitest browser otelCarrier token RCE
Vitest browser mode served the otelCarrier query parameter inside an inline
module script on the browser-runner page. In affected @vitest/browser
versions, that value was treated as JavaScript source. A crafted runner URL can
execute script in the Vitest server origin, recover the browser API token, and
then call privileged Vitest browser APIs. In a default local watch setup, those
APIs can be chained to write project files and trigger Node-side code
execution through configuration reload.
This is a development and CI exposure, not a production web app dependency in the usual sense. The dangerous shape is a browser-mode test server reachable by untrusted users, browsers, preview links, tunnel URLs, shared dev containers, remote workstations, or CI jobs that hold package, cloud, repository, or model provider credentials.
When to use it
Use this recipe when a repository uses Vitest Browser Mode in local dev, devcontainers, remote workstations, preview environments, or CI runners where test servers may be reachable beyond loopback. It is designed for source-code and config remediation, developer-tooling exposure review, credential hygiene, and evidence that browser-runner APIs cannot be reached or abused by untrusted users.
Inputs
@vitest/browserandvitestversions, lockfiles, workspace package layout, test scripts, browser-mode config, devcontainer/CI commands, and generated dependency reports.- Source/config paths that set
--browser,--host,browser.api.host,allowWrite,allowExec, environment variables, tunnels, or preview links. - Regression fixtures or safe checks for fixed versions, loopback binding, disabled privileged APIs on exposed runners, and absence of crafted runner URL handling.
- Boundary evidence: dev/CI secret exposure, package/cloud/repository tokens, forwarded ports, shared runner owners, logs, and rollout owner.
Affected versions
| Package | Vulnerable versions | Fixed versions |
|---|---|---|
@vitest/browser |
>=4.0.17, <4.1.6 |
4.1.6+ |
@vitest/browser |
>=5.0.0-beta.0, <5.0.0-beta.3 |
5.0.0-beta.3+ |
Indicator-of-exposure
- The repository depends on
@vitest/browserin an affected range. - Test scripts, task runners, devcontainer commands, CI jobs, or docs run Vitest browser mode, especially in watch mode.
- Vitest browser servers bind to non-loopback hosts through
--host,--api.host,browser.api.host,0.0.0.0, devcontainer forwarding, Codespaces, tunnels, preview environments, or shared workstations. - Browser-mode jobs run with sensitive environment variables, package-manager tokens, cloud credentials, repository write tokens, model-provider keys, source checkouts, generated artifacts, or mounted secrets.
- Config leaves privileged browser API operations enabled on a network-reachable server.
Quick checks:
rg -n "@vitest/browser|vitest.*browser|--browser|browser:\\s*\\{|browser\\.enabled|__vitest_test__|otelCarrier|VITEST_API_TOKEN|api\\.host|allowWrite|allowExec|0\\.0\\.0\\.0|--host" .
npm ls @vitest/browser vitest
pnpm why @vitest/browser vitest
yarn why @vitest/browser vitest
Windows:
rg -n "@vitest/browser|vitest.*browser|--browser|browser:\\s*\\{|browser\\.enabled|__vitest_test__|otelCarrier|VITEST_API_TOKEN|api\\.host|allowWrite|allowExec|0\\.0\\.0\\.0|--host" .
npm ls @vitest/browser vitest
pnpm why @vitest/browser vitest
yarn why @vitest/browser vitest
Do not open crafted Vitest runner URLs, recover VITEST_API_TOKEN, connect to
Vitest WebSocket APIs, or write test/config files through the browser API during
triage.
Remediation strategy
- Upgrade every controlled
@vitest/browserdependency, lockfile, workspace, CI image, devcontainer, and generated dependency report to4.1.6+or5.0.0-beta.3+on the selected release line. - Keep
vitest,@vitest/browser,@vitest/ui, Vite plugins, and lockfiles on compatible versions so the browser runner resolves the patched package. - Bind browser-mode servers to loopback by default. Require an explicit,
reviewed exception before
--host,--api.host, forwarded ports, or tunnel URLs expose a Vitest server. - Disable privileged write/execute operations on any network-reachable Vitest
server. In fixed versions, set or verify policy for
allowWriteandallowExecinstead of relying on UI-only conventions. - Remove secrets from browser-mode test environments where practical. Use read-only package tokens, short-lived CI credentials, and isolated source workspaces for test runners.
- Review devcontainer, remote IDE, and CI logs for unexpected access if an affected browser-mode server was exposed.
The prompt
Model context: this prompt was generated by GPT 5.5 Extra High reasoning.
You are remediating CVE-2026-47428 / GHSA-2h32-95rg-cppp, a Vitest browser
mode inline script injection that can expose the Vitest browser API token and
lead to project-file writes or Node-side execution. Produce exactly one output:
- A reviewer-ready PR/change request that upgrades affected Vitest browser
packages, prevents network exposure of privileged browser-mode APIs, adds
safe regression checks, refreshes generated artifacts, and documents operator
cleanup, or
- TRIAGE.md if this repository does not use affected Vitest browser mode or
cannot patch the owned test environment.
## Rules
- Scope only CVE-2026-47428 / GHSA-2h32-95rg-cppp and directly related Vitest
browser-mode exposure.
- Treat `VITEST_API_TOKEN`, CI tokens, package tokens, repository tokens,
cloud credentials, model-provider keys, environment variables, source files,
generated artifacts, and test output as sensitive.
- Do not open exploit URLs, inject `otelCarrier` payloads, recover browser API
tokens, call Vitest WebSocket APIs, write files through Vitest, or trigger
config reload code execution.
- Do not remove test coverage, browser-mode tests, provenance checks, or CI
gates just to silence the alert.
- Do not auto-merge.
## Steps
1. Inventory every `@vitest/browser`, `vitest`, `@vitest/ui`, Vite test
workspace, lockfile, devcontainer, CI image, Dockerfile, package manager
cache, generated dependency report, SBOM, and test script controlled by this
repository.
2. Determine every resolved `@vitest/browser` version. A target is vulnerable
if it resolves to `>=4.0.17, <4.1.6` or `>=5.0.0-beta.0, <5.0.0-beta.3`.
3. Search for browser-mode execution paths:
`--browser`, browser-mode config, watch mode, `api.host`, `--host`,
forwarded ports, devcontainer ports, Codespaces ports, tunnels, preview
links, browser provider setup, and scripts that start Vitest servers.
4. Classify each server binding:
loopback-only local development, trusted CI without inbound access, remote
dev workspace, shared workstation, preview environment, tunneled server, or
internet/network-exposed test server.
5. If the repository does not use `@vitest/browser` or only contains unrelated
docs, stop with `TRIAGE.md` listing checked files and the external owner if
a platform image supplies Vitest.
6. Upgrade affected packages to `@vitest/browser 4.1.6+` or
`5.0.0-beta.3+`. Keep `vitest`, `@vitest/ui`, plugins, and lockfiles
compatible. Refresh package locks, generated dependency reports, SBOMs,
devcontainer images, and CI caches as this repository normally does.
7. Harden browser-mode server exposure:
- bind to loopback by default;
- remove accidental `0.0.0.0`, forwarded port, or tunnel defaults;
- require an explicit reviewed opt-in for non-loopback browser-mode servers;
- disable `allowWrite` and `allowExec` when the API is not strictly local;
- document any exception and its owner.
8. Reduce token blast radius in test environments:
- remove long-lived package, cloud, model-provider, and repository tokens
from browser-mode jobs;
- prefer read-only or short-lived tokens;
- isolate source workspaces used by browser-mode watch servers;
- avoid running browser-mode servers in jobs that can publish releases or
mutate deployment state.
9. Add safe regression checks that do not exploit the issue:
- resolved `@vitest/browser` is patched;
- scripts/config do not bind browser-mode API to non-loopback hosts unless
an explicit allow-list is present;
- network-exposed configs set privileged write/execute operations disabled;
- browser-mode jobs do not receive long-lived secret-bearing environments;
- logs and validation output omit tokens and environment values.
10. Add a PR body section named `CVE-2026-47428 operator actions` that states:
- affected Vitest package versions before and after;
- where browser mode runs;
- whether any server was network-reachable or forwarded;
- which privileged API operations remain enabled, if any;
- which CI, package, cloud, model-provider, or repository tokens may have
been present and whether rotation is needed;
- which validation commands passed.
11. Run available validation: package install, lockfile integrity, unit tests,
browser-mode tests without exploit input, lint/typecheck, CI config lint,
dependency/security scans, SBOM refresh, and devcontainer or image checks.
12. Use PR title:
`fix(sec): remediate CVE-2026-47428 in Vitest browser mode`.
## Stop conditions
- No affected `@vitest/browser` package, browser-mode script, image, or
workspace is controlled by this repository.
- A fixed Vitest browser package cannot be consumed without a broader test
framework migration.
- The only affected runtime is supplied by another platform owner; document the
owner, required fixed version, and exposure assumptions in `TRIAGE.md`.
- Verification would require opening crafted runner URLs, reading
`VITEST_API_TOKEN`, calling WebSocket APIs, writing files through Vitest, or
exposing live secrets.
- Validation fails for unrelated pre-existing reasons; document those failures
instead of broadening scope.
Output contract
- A reviewer-ready PR or change request that upgrades
@vitest/browser, refreshes lockfiles/generated artifacts, restricts browser runners to safe bindings, documents credential exposure review, and adds safe config checks. - Or a
TRIAGE.mdfile that lists inspected package files/config, owner, observed version, browser-runner exposure boundary, required fix, and residual risk. - The output must include exact validation commands and must not recover real
VITEST_API_TOKENvalues, open crafted runner URLs, call privileged browser APIs, or write project files during triage.
Verification - what the reviewer looks for
- No controlled lockfile, workspace, devcontainer, CI image, SBOM, or generated
dependency report resolves affected
@vitest/browserversions. - Browser-mode servers bind to loopback unless a reviewed exception exists.
- Network-reachable Vitest servers have privileged write and execute operations disabled.
- Tests or policy checks catch accidental host exposure and stale package pins.
- Operator notes cover token cleanup if exposed browser-mode servers had access to secret-bearing test environments.
Watch for
- Updating
package.jsonwhile lockfiles, CI images, devcontainers, or cached package layers still install the vulnerable browser package. - Treating a dev server as harmless while it runs in a remote workspace with repository or package-publish tokens.
- Fixing only
vitestwhile@vitest/browserremains pinned in another workspace. - Leaving
--host 0.0.0.0, forwarded ports, or tunnel URLs in scripts used by agents and shared CI jobs. - Regression tests that prove browser tests still run but never assert safe binding and privileged API policy.
Related recipes
- Source code secrets and data exposure audit
- Source code supply chain build integrity audit
- Source code attack surface map
- SAST finding triage and fix
References
- GitHub Advisory: https://github.com/advisories/GHSA-2h32-95rg-cppp
- Vitest vendor advisory: https://github.com/vitest-dev/vitest/security/advisories/GHSA-2h32-95rg-cppp
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-47428