Moderate severityCISA KEVNVD Advisory· Published Mar 31, 2025· Updated Jan 23, 2026
Vite has a `server.fs.deny` bypassed for `inline` and `raw` with `?import` query
CVE-2025-31125
Description
Vite is a frontend tooling framework for javascript. Vite exposes content of non-allowed files using ?inline&import or ?raw?import. Only apps explicitly exposing the Vite dev server to the network (using --host or server.host config option) are affected. This vulnerability is fixed in 6.2.4, 6.1.3, 6.0.13, 5.4.16, and 4.5.11.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
vitenpm | >= 6.2.0, < 6.2.4 | 6.2.4 |
vitenpm | >= 6.1.0, < 6.1.3 | 6.1.3 |
vitenpm | >= 6.0.0, < 6.0.13 | 6.0.13 |
vitenpm | >= 5.0.0, < 5.4.16 | 5.4.16 |
vitenpm | < 4.5.11 | 4.5.11 |
Affected products
1Patches
159673137c45afix: fs check in transform middleware (#19761)
3 files changed · +82 −3
packages/vite/src/node/server/middlewares/transform.ts+7 −3 modified@@ -12,10 +12,8 @@ import { isJSRequest, normalizePath, prettifyUrl, - rawRE, removeImportQuery, removeTimestampQuery, - urlRE, } from '../../utils' import { send } from '../send' import { ERR_LOAD_URL, transformRequest } from '../transformRequest' @@ -45,6 +43,11 @@ const debugCache = createDebugger('vite:cache') const knownIgnoreList = new Set(['/', '/favicon.ico']) const trailingQuerySeparatorsRE = /[?&]+$/ +// TODO: consolidate this regex pattern with the url, raw, and inline checks in plugins +const urlRE = /[?&]url\b/ +const rawRE = /[?&]raw\b/ +const inlineRE = /[?&]inline\b/ + /** * A middleware that short-circuits the middleware chain to serve cached transformed modules */ @@ -176,7 +179,8 @@ export function transformMiddleware( ) if ( (rawRE.test(urlWithoutTrailingQuerySeparators) || - urlRE.test(urlWithoutTrailingQuerySeparators)) && + urlRE.test(urlWithoutTrailingQuerySeparators) || + inlineRE.test(urlWithoutTrailingQuerySeparators)) && !ensureServingAccess( urlWithoutTrailingQuerySeparators, server,
playground/fs-serve/root/src/index.html+51 −0 modified@@ -23,6 +23,8 @@ <h2>Unsafe Fetch</h2> <pre class="unsafe-fetch-8498"></pre> <pre class="unsafe-fetch-8498-2-status"></pre> <pre class="unsafe-fetch-8498-2"></pre> +<pre class="unsafe-fetch-import-inline-status"></pre> +<pre class="unsafe-fetch-raw-query-import-status"></pre> <h2>Safe /@fs/ Fetch</h2> <pre class="safe-fs-fetch-status"></pre> @@ -45,6 +47,8 @@ <h2>Unsafe /@fs/ Fetch</h2> <pre class="unsafe-fs-fetch-8498"></pre> <pre class="unsafe-fs-fetch-8498-2-status"></pre> <pre class="unsafe-fs-fetch-8498-2"></pre> +<pre class="unsafe-fs-fetch-import-inline-status"></pre> +<pre class="unsafe-fs-fetch-import-inline-wasm-init-status"></pre> <h2>Nested Entry</h2> <pre class="nested-entry"></pre> @@ -160,6 +164,24 @@ <h2>Denied</h2> console.error(e) }) + // outside of allowed dir with import inline + fetch(joinUrlSegments(base, '/unsafe.txt?import&inline')) + .then((r) => { + text('.unsafe-fetch-import-inline-status', r.status) + }) + .catch((e) => { + console.error(e) + }) + + // outside of allowed dir with raw query import + fetch(joinUrlSegments(base, '/unsafe.txt?raw?import')) + .then((r) => { + text('.unsafe-fetch-raw-query-import-status', r.status) + }) + .catch((e) => { + console.error(e) + }) + // imported before, should be treated as safe fetch(joinUrlSegments(base, joinUrlSegments('/@fs/', ROOT) + '/safe.json')) .then((r) => { @@ -247,6 +269,35 @@ <h2>Denied</h2> console.error(e) }) + // outside of root inline + fetch( + joinUrlSegments( + base, + joinUrlSegments('/@fs/', ROOT) + '/root/unsafe.txt?import&inline', + ), + ) + .then((r) => { + text('.unsafe-fs-fetch-import-inline-status', r.status) + }) + .catch((e) => { + console.error(e) + }) + + // outside of root inline, faux wasm?init + fetch( + joinUrlSegments( + base, + joinUrlSegments('/@fs/', ROOT) + + '/root/unsafe.txt?import&?inline=1.wasm?init', + ), + ) + .then((r) => { + text('.unsafe-fs-fetch-import-inline-wasm-init-status', r.status) + }) + .catch((e) => { + console.error(e) + }) + // outside root with special characters #8498 fetch( joinUrlSegments(
playground/fs-serve/__tests__/fs-serve.spec.ts+24 −0 modified@@ -67,6 +67,18 @@ describe.runIf(isServe)('main', () => { expect(await page.textContent('.unsafe-fetch-8498-2-status')).toBe('404') }) + test('unsafe fetch import inline', async () => { + expect(await page.textContent('.unsafe-fetch-import-inline-status')).toBe( + '403', + ) + }) + + test('unsafe fetch raw query import', async () => { + expect( + await page.textContent('.unsafe-fetch-raw-query-import-status'), + ).toBe('403') + }) + test('safe fs fetch', async () => { expect(await page.textContent('.safe-fs-fetch')).toBe(stringified) expect(await page.textContent('.safe-fs-fetch-status')).toBe('200') @@ -120,6 +132,18 @@ describe.runIf(isServe)('main', () => { expect(await page.textContent('.unsafe-fs-fetch-8498-2-status')).toBe('404') }) + test('unsafe fs fetch import inline', async () => { + expect( + await page.textContent('.unsafe-fs-fetch-import-inline-status'), + ).toBe('403') + }) + + test('unsafe fs fetch import inline wasm init', async () => { + expect( + await page.textContent('.unsafe-fs-fetch-import-inline-wasm-init-status'), + ).toBe('403') + }) + test('nested entry', async () => { expect(await page.textContent('.nested-entry')).toBe('foobar') })
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-4r4m-qw57-chr8ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-31125ghsaADVISORY
- github.com/vitejs/vite/commit/59673137c45ac2bcfad1170d954347c1a17ab949ghsax_refsource_MISCWEB
- github.com/vitejs/vite/security/advisories/GHSA-4r4m-qw57-chr8ghsax_refsource_CONFIRMWEB
- www.cisa.gov/known-exploited-vulnerabilities-catalogghsaWEB
News mentions
0No linked articles in our index yet.