On October 21, 2026, the GitHub Advisory Database published CVE-2026-112948 (GHSA-p458-7748-mcp3), exposing a critical file access misconfiguration in Vitest 5 dev servers.
Under specific developer configurations—specifically when running the interactive UI (vitest --ui), Browser Mode (@vitest/browser), or when enabling the remote api flag—Vitest's underlying HTTP server failed to apply Vite's default server.fs.deny rules.
The outcome: sensitive project assets that Vite ordinarily guards by default—including .env, .env.local, .npmrc, private SSL certificates, .git metadata, and Vitest's internal authentication token file (.vitest-secret-token)—could be fetched over plain HTTP by any client reachable on the network or by a malicious browser tab via cross-origin requests.
Here is an engineering audit of what went wrong, how to check if your workstation was exposed, and how to safely rotate compromised tokens.
The Vulnerability Breakdown: Why server.fs.deny Was Overridden
In a standard Vite configuration, server.fs.deny protects sensitive paths using built-in globs:
// Vite's built-in default deny patterns:
['.env', '.env.*', '*.{crt,pem}', '**/.git/**', '**/.npmrc']
When Vitest 5 introduced its internal API server and UI token authentication (.vitest-secret-token), it programmatically appended its token file to the deny list. However, two underlying Vite runtime behaviors caused a silent bypass:
-
Premature Array Overwrite: Vite only injects its default deny list when
server.fs.denyis completelyundefined. When Vitest assigned an array containing only['.vitest-secret-token'], Vite's default rules were discarded rather than merged. -
Matcher Pre-Compilation: Vite compiles the
denylist into an internal regex matcher during config resolution. Dynamic runtime mutations pushed later had zero effect on the active HTTP file serving pipeline.
If you ran vitest --ui on a local network or tested apps inside a browser with multi-tab sessions, any script capable of hitting localhost:51204 could scrape your secret keys.
Am I Affected?
The advisory confirms:
-
Affected: Vitest 5 running with
--ui,@vitest/browser, orapi: trueinvitest.config.ts. -
Not Affected: Headless command-line runs (
vitest runor simplevitestin terminal mode) because they do not spawn an HTTP listener.
Immediate Remediation Steps
Step 1: Upgrade Vitest to Patched Release
Vitest maintainers released patched versions addressing the matcher compilation flaw. Upgrade Vitest alongside its peer dependencies:
npm install -D vitest@latest @vitest/ui@latest @vitest/browser@latest
# or with pnpm:
pnpm update vitest @vitest/ui @vitest/browser
Step 2: Audit and Invalidate Leaked Secrets
If you ran Vitest UI on shared Wi-Fi (coworking spaces, cafes) or had active third-party tabs open during browser mode tests, treat all keys residing in your .env as compromised.
Common credentials stored in .env requiring immediate rotation:
- Cloud provider access tokens (AWS, GCP, Cloudflare)
- Database credentials (Postgres, Redis, MongoDB connection URIs)
- OAuth 2.0 Client Secrets and JWT Signing Passphrases
- Third-party API keys (Stripe, Resend, GitHub PATs)
Step 3: Rotate Tokens with High-Entropy CSPRNG
When re-issuing API tokens or generating new application secrets, never use pseudo-random generators (Math.random()) or web services that log requests to central databases.
Use the Web Crypto API (crypto.getRandomValues) to generate cryptographically unguessable keys with adequate entropy:
/**
* Generate a 256-bit high-entropy secret token (RFC 6750 compliant)
*/
function generateSecureToken(byteLength = 32): string {
const bytes = new Uint8Array(byteLength);
crypto.getRandomValues(bytes);
return Array.from(bytes)
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}
// Example Output: 64-char Hex (256 bits of entropy)
console.log(generateSecureToken(32));
If you need ready-to-copy Bearer tokens (sk_live_...), RFC 4648 Base32 keys (for TOTP/2FA secrets), or URL-safe Base64URL tokens without writing boilerplate code, you can use the free, client-side DevOmniTools Token Generator — all tokens are generated strictly in browser memory via CSPRNG with zero server calls.
Likewise, if you need to inspect decoded JWT headers and audience claims from your rotated tokens to verify expiration and issuer claims without sending your payload across the web, use the DevOmniTools Offline JWT Decoder.
Defensive Coding: Explicitly Guarding server.fs.deny
Even after updating, you can explicitly reinforce your vite.config.ts or vitest.config.ts to ensure sensitive files can never be served under any circumstances:
import { defineConfig } from 'vitest/config';
export default defineConfig({
server: {
fs: {
strict: true,
deny: [
'**/.env*',
'**/*.pem',
'**/*.key',
'**/.git/**',
'**/.npmrc',
'**/.vitest-secret-token'
]
}
},
test: {
// your test settings
}
});
Summary Checklist
- [ ] Update
vitestand@vitest/uito the latest security patch. - [ ] Revoke and re-issue all API tokens present in
.envfiles accessed during Vitest UI sessions. - [ ] Verify that
server.fs.strict: trueis configured in your project settings. - [ ] Check Git history to ensure no
.envfiles were accidentally committed during debugging.


Top comments (0)