VYPR
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.

PackageAffected versionsPatched versions
vitenpm
>= 6.2.0, < 6.2.46.2.4
vitenpm
>= 6.1.0, < 6.1.36.1.3
vitenpm
>= 6.0.0, < 6.0.136.0.13
vitenpm
>= 5.0.0, < 5.4.165.4.16
vitenpm
< 4.5.114.5.11

Affected products

1

Patches

1
59673137c45a

fix: fs check in transform middleware (#19761)

https://github.com/vitejs/vitepatakMar 31, 2025via ghsa
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

News mentions

0

No linked articles in our index yet.