Microweber CMS Unauthenticated Path Traversal → Arbitrary File Read (CVE-2026-65694)
Published: 2026-07-31 • Researcher: Bobur Abdugafforov (Mahadsec)
- Severity
- High
- CVE
- CVE-2026-65694 (VulnCheck advisory)
- Category
- web
- Affected product
- Microweber CMS — ServeStaticFileContoller::serveFromUserfiles()
- Affected versions
- Microweber 0 through 2.0.20 (all released versions); vulnerable line still present on current master as of ingestion
- Disclosed
- 2026-07-31
- Patch status
- Patched
Tags
References
Archive entry
intelseclab/poc-archiveOn this page
Metadata
| Field | Value |
|---|---|
| Date Added | 2026-07-31 |
| Last Updated | 2026-07-31 |
| Author / Researcher | Bobur Abdugafforov (Mahadsec) |
| CVE / Advisory | CVE-2026-65694 (VulnCheck advisory) |
| Category | web |
| Severity | High |
| CVSS Score | 7.5 (CVSS 3.1, AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N); 8.7 (CVSS 4.0) |
| Status | Unpatched |
| Tags | microweber, path-traversal, cwe-22, unauthenticated, arbitrary-file-read, laravel, query-string-override |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | Microweber CMS — ServeStaticFileContoller::serveFromUserfiles() |
| Versions Affected | Microweber 0 through 2.0.20 (all released versions); vulnerable line still present on current master as of ingestion |
| Language / Platform | PHP / Laravel |
| Authentication Required | No |
| Network Access Required | Yes — any reachable HTTP(S) endpoint serving the app |
Summary
Microweber CMS exposes an unauthenticated GET /userfiles/{path} route intended to serve files from its userfiles/ upload directory. The controller reads the path via $request->path — a Laravel magic-property accessor that falls back to the request’s query-string bag rather than the route-bound segment — so an attacker-supplied ?path= query parameter silently overrides the intended {path} route value. The resulting path is passed through normalize_path(), which does not strip .. sequences, and the route carries no auth middleware. The combination lets any unauthenticated remote attacker read arbitrary files off the filesystem, including the Laravel .env (leaking APP_KEY, database credentials, mail/cloud secrets) and OS files such as /etc/passwd.
Vulnerability Details
Root Cause
In src/MicroweberPackages/App/Http/Controllers/ServeStaticFileContoller.php:
| |
registered as:
| |
Two independent bugs stack:
- Input source confusion.
$request->pathis a property access, not the$request->path()method call. Laravel resolves undefined properties onRequestthrough__get, which falls back toArr::get($this->all(), 'path', fn() => $this->route('path'))— meaning apathkey present anywhere in the request’s input bag (query string or POST body) takes priority over the actual bound{path}route segment. An attacker can therefore leave the route segment as an arbitrary, non-existent value and smuggle the real traversal payload in through?path=. - No canonicalization.
normalize_path()only collapses duplicate slashes; it never resolves or strips..components, and the controller never verifies the resolved path stays insideuserfiles_path(). The filesystem layer then happily resolves the..segments outside the intended directory.
The controller blocks only files ending in .php, .phtml, or .php7 (its skip_ext list) — so PHP source is not directly readable via this route, but every other file type is (.env, logs, keys, SQLite databases, YAML/JSON configuration, /etc/passwd, etc.).
Attack Vector
Unauthenticated GET request against the public /userfiles/{path} route, where the route segment is a random/garbage value (so it does not need to correspond to any real file) and the real traversal payload rides in the path query-string parameter:
GET /userfiles/<random-nonexistent-segment>?path=../../../../etc/passwd HTTP/1.1
Host: targetTraversal depth and encoding (../, ..%2f, %2e%2e%2f, etc.) are auto-detected by the PoC to accommodate different deployment/proxy normalization behavior.
Impact
Unauthenticated arbitrary file read. On a default Laravel-backed deployment this means the .env file is directly retrievable, exposing APP_KEY (enabling session/cookie forgery), database credentials, mail credentials, and any cloud/storage keys configured in the app — effectively a full compromise of the instance’s secrets without any prior authentication. OS-level files such as /etc/passwd are also readable, subject only to the permissions of the web-server process user.
Environment / Lab Setup
Target: Microweber CMS <= 2.0.20 (or current master), deployed with the recommended
public/ document root (shipped public/.htaccess, or an nginx front controller
routing /userfiles/* into the Laravel app)
Attacker: Python 3 + requests
Tools: poc.py (this folder)Setup Steps
| |
Proof of Concept
See
poc.py(full, unmodified, 253 lines),requirements.txt, andupstream-README.mdin this folder — mirrored from abdugafforov-bobur/CVE-2026-65694-PoC. Verified before ingestion: read the full request logic directly — it buildsGET /userfiles/<random-nonexistent-segment>?path=<traversal>, deliberately routing to a fake path segment while smuggling the real traversal through thepathquery parameter, which is an exact match for the documented property-vs-route-binding override bug rather than a generic traversal guess. The script auto-detects traversal depth and encoding, uses/etc/passwdorwindows/win.inicontent as a vulnerability oracle in itscheck()routine, and supports arbitrary file read (stdout) or download to disk. Only third-party dependency isrequests; no obfuscation, no unrelated network calls, no destructive default behavior.
Step-by-Step Reproduction
Install the dependency
Shell script1pip install -r requirements.txtCheck whether a target is vulnerable (does not dump file contents)
Shell script1python3 poc.py -u http://TARGET --checkRead an arbitrary file to stdout
Shell script1 2python3 poc.py -u http://TARGET -r /etc/passwd python3 poc.py -u http://TARGET -r .envDownload a file to disk
Shell script1python3 poc.py -u http://TARGET -d /etc/passwd -o passwd.txt
Exploit Code
| |
The underlying request is simply:
GET /userfiles/<random>?path=../../../../etc/passwd HTTP/1.1
Host: targetExpected Output
Microweber CMS - Unauthenticated Arbitrary File Read
CVE-2026-65694 ( GET /userfiles/ ?path= traversal )
by Bobur Abdugafforov
[*] Testing target: http://target:8080
[+] 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
...Screenshots / Evidence
Not applicable — text-based HTTP PoC, no GUI evidence captured.
Detection & Indicators of Compromise
"GET /userfiles/<random-looking-segment>?path=..%2f..%2f..%2f..%2fetc%2fpasswd HTTP/1.1" 200Remediation
| Action | Detail |
|---|---|
| Patch | No vendor-released version yet. A fix is proposed in upstream PR microweber/microweber #1181 (open, submitted by the reporter) but had not merged and no version had been cut as of this ingestion. |
| Workaround | Add a reverse-proxy/WAF rule to strip or reject requests to /userfiles/* that carry a path query-string parameter, and/or block .. sequences in that parameter. Restrict filesystem permissions of the web-server user to minimize blast radius. |
| Code-level fix (per proposed PR) | Read the bound route parameter ($request->route('path')) instead of the input property, canonicalize with realpath(), and verify the resolved path stays inside userfiles_path() before serving it. |
References
Notes
Verified before ingestion per this archive’s standard process: the real poc.py file contents were read directly (not taken on faith from the upstream README) and its request-construction logic — GET /userfiles/<random-nonexistent-segment>?path=<traversal> — is an exact match for the documented property-vs-route-binding override bug, not a generic traversal template. The PoC author’s GitHub account (abdugafforov-bobur) was cross-checked against the upstream fix PR and confirmed to be the same person who filed microweber/microweber PR #1181 — i.e., the reporter who found the bug also wrote both the proposed patch and this PoC, which is a strong authenticity signal. No obfuscation, scam, dropper, or phantom-exploit signals were found: the script is a plain requests-based HTTP client with no eval/exec beyond its stated purpose and no curl-pipe-to-shell installer.
Flagging explicitly: as of this ingestion, NO VENDOR PATCH EXISTS for CVE-2026-65694. The fix PR (microweber/microweber #1181) was still open and unmerged, and no patched Microweber version had been released. Status is marked Unpatched accordingly. This entry should be revisited once the PR merges and a fixed version is cut, to update Status/Remediation and record the patched version number.
| |