============================================================================================================================================= | # Title : Voyager 1.8.0 Arbitrary File Upload Leading to Potential Remote Code Execution | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits) | | # Vendor : https://github.com/thedevdojo/voyager | ============================================================================================================================================= [+] Affected Component : TCG\Voyager\Http\Controllers\VoyagerController::upload() [+] Affected Versions : Voyager prior to hardening of upload validation [+] Confirmed on default installations using: public storage disk storage:link enabled Image upload via Rich Text Editor (TinyMCE) [+] Vulnerability Type Arbitrary File Upload Insufficient MIME Validation Trusting Client-Supplied File Extension Potential Remote Code Execution (RCE) [+] Description : The Voyager upload endpoint fails to properly validate uploaded image files. The application relies on: guessClientExtension() client-controlled original filename extension-based allowlist [+] An attacker with minimal privileges (any role allowed to upload images in a Rich Text Box) can upload a polyglot file masquerading as an image while embedding server-side executable code. Because the file is stored using the original extension and placed in a web-accessible directory, this can lead to arbitrary code execution under certain server configurations. [+] Vulnerable Logic : $ext = $file->guessClientExtension(); if (in_array($ext, ['jpeg', 'jpg', 'png', 'gif'])) { $image->encode($file->getClientOriginalExtension(), 75); Storage::disk(...)->put($fullPath, (string) $image, 'public'); } [+] Issues : guessClientExtension() is client-influenced Original extension is reused during encoding No signature-based image verification Publicly accessible storage path [+] POC : [+] bypass logic only Step 1 – Prepare a Polyglot Image Create a file that: Starts with a valid image header (e.g. GIF/JPEG) Contains non-executable marker content for verification [+] Example : GIF89a [+] Save as: test.php.gif Note: No PHP code is required to demonstrate the flaw. Step 2 – Upload via Voyager Editor Login as any user with Rich Text Box upload permission [+] Insert image via editor : Upload test.php.gif Step 3 – Observe Stored File The file will be stored as: /storage/{slug}/{date}/test.php.gif [+] This confirms : Extension preservation Lack of enforced re-encoding Client filename trust Step 4 – Impact Confirmation If server-side execution is enabled for misconfigured MIME handlers or future changes: This upload path becomes a code execution primitive Risk escalates from File Upload → RCE [+] Impact An attacker may: Upload arbitrary files Bypass intended image-only restriction Potentially execute server-side code Escalate privileges or compromise the application [+] Mitigation : Force server-side extension $image->encode('jpg', 75); Validate image via signature (magic bytes) Reject mixed or double extensions Store uploads outside web root Enforce strict MIME validation Add upload size & rate limits Greetings to :===================================================================================== jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)| ===================================================================================================