User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration <= 4.2.8 - Authenticated (Author+) Arbitrary File Upload
Description
The User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration plugin for WordPress is vulnerable to arbitrary file uploads due to incorrect file type validation in the 'WPUF_Admin_Settings::check_filetype_and_ext' function and in the 'Admin_Tools::check_filetype_and_ext' function in all versions up to, and including, 4.2.8. This makes it possible for authenticated attackers, with Author-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
<=4.2.8What Changed in the Fix
Changes introduced in v4.2.9
Source Code
WordPress.org SVNThis research plan outlines the steps to analyze and exploit **CVE-2026-1565**, an arbitrary file upload vulnerability in the "WP User Frontend" plugin. ### 1. Vulnerability Summary The vulnerability exists in the `WPUF_Admin_Settings` and `Admin_Tools` classes, specifically within the `check_filet…
Show full research plan
This research plan outlines the steps to analyze and exploit CVE-2026-1565, an arbitrary file upload vulnerability in the "WP User Frontend" plugin.
1. Vulnerability Summary
The vulnerability exists in the WPUF_Admin_Settings and Admin_Tools classes, specifically within the check_filetype_and_ext functions. These functions are used as filters for the WordPress core wp_check_filetype_and_ext hook. The logic in these functions incorrectly validates or overrides the results of WordPress's native file type checks. By manipulating the filename or MIME type, an authenticated user with Author-level access or above can bypass security restrictions and upload executable PHP files to the server.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - AJAX Action:
wpuf_import_forms(registered inadmin/class-admin-settings.php) - HTTP Parameter:
import_file(the multipart file upload field) - Authentication: Authenticated, Author level and above.
- Precondition: The plugin must be active. By default, the
wpuf_admin_rolemight be restricted to administrators, but the CVE description specifies "Author+", implying that in many configurations or by design, these users can access the import functionality.
3. Code Flow
- Entry Point: The attacker sends a
POSTrequest toadmin-ajax.phpwithaction=wpuf_import_forms. - Handler:
WPUF_Admin_Settings::import_forms()is invoked. - Upload Trigger: Inside
import_forms(), the plugin callswp_handle_upload()to process$_FILES['import_file']. - Vulnerable Filter: During
wp_handle_upload(), WordPress triggers thewp_check_filetype_and_extfilter. The plugin has registeredWPUF_Admin_Settings::check_filetype_and_ext()(orAdmin_Tools::check_filetype_and_ext) to this filter. - Logic Failure: The function
check_filetype_and_ext($data, $file, $filename, $mimes)likely checks if the file is intended to be a JSON file (the expected format for form imports). If the logic incorrectly trusts the extension (e.g., checking for.jsonanywhere in the name) or fails to validate the actual content while overriding the$data['ext']and$data['type']values, it forces WordPress to treat a.phpfile as a valid.jsonupload. - Persistence:
wp_handle_upload()moves the file to thewp-content/uploads/YYYY/MM/directory. Even if the subsequent "import" logic (which expects JSON) fails, the PHP file remains on the server.
4. Nonce Acquisition Strategy
The AJAX action wpuf_import_forms is likely protected by a nonce. Based on the plugin structure in admin/class-admin-settings.php, the import functionality is located in the "Tools" menu.
- Identify Location: The tools page is at
wp-admin/admin.php?page=wpuf_tools. - Navigate: Use
browser_navigateto access the Tools page as an Author-level user. - Extract Nonce: The nonce is likely localized via
wp_localize_script. Search for script tags containingwpuf_adminorwpuf_toolsobjects.- Candidate JS Variable:
window.wpuf_adminorwindow.wpuf_import_nonce. - Execution:
// Example guess based on common WPUF patterns browser_eval("window.wpuf_admin?.nonce || document.querySelector('#wpuf_import_forms_nonce')?.value")
- Candidate JS Variable:
- Verification: If no nonce check is found in the
import_formsfunction (via manual inspection of theadmin/class-admin-settings.phpfull source), the check may be missing entirely.
5. Exploitation Strategy
- Preparation: Prepare a PHP shell payload named
exploit.php. - Alternative Filename: If the filter specifically looks for
.json, useexploit.php.json. If the filter is flawed, it will allow the upload and keep the.phpextension in the final path or allow a double extension. - Request Construction:
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: multipart/form-data - Body Parameters:
action:wpuf_import_forms_wpnonce:[EXTRACTED_NONCE]import_file:[FILE_CONTENT](filename:exploit.php)
- URL:
- Execution: Send the request using
http_request. - Path Discovery: The response from
wp_ajax_wpuf_import_formsusually returns the result of the import. If it fails due to invalid JSON, look for the file path in thewp-content/uploads/directory for the current year/month.
6. Test Data Setup
- Create Author User:
wp user create attacker attacker@example.com --role=author --user_pass=password - Ensure Access (If needed): If the plugin restricts the Tools page to admins, elevate the Author role or adjust WPUF settings:
wp option update wpuf_admin_role author - Identify Current Upload Dir:
wp eval 'echo wp_upload_dir()["url"];'
7. Expected Results
- Success Response: The AJAX request returns a success message or a JSON error indicating the file was uploaded but could not be parsed as JSON.
- File Presence: A file named
exploit.php(or similar) is created in/var/www/html/wp-content/uploads/YYYY/MM/. - RCE: Accessing
http://localhost:8080/wp-content/uploads/YYYY/MM/exploit.phpexecutes the PHP code.
8. Verification Steps
- Check Filesystem:
find /var/www/html/wp-content/uploads/ -name "exploit.php" - Test Execution: Use
http_requestto GET the uploaded file and check for the payload's output (e.g.,uid=...ifidcommand was used).
9. Alternative Approaches
- Double Extension: Try
exploit.json.phporexploit.php.json. - Admin Tools Endpoint: The description mentions
Admin_Tools::check_filetype_and_ext. Check if there is a separate AJAX action for "Tools" (e.g.,wpuf_import_tools) that uses a different class. - MIME Spoofing: Provide
Content-Type: application/jsonin the multipart part for the PHP file to trick thecheck_filetype_and_extlogic if it relies on the browser-provided MIME type.
Summary
The WP User Frontend plugin for WordPress is vulnerable to arbitrary file uploads due to a logic flaw in the file validation filters used during form imports. Authenticated attackers with Author-level access or higher can bypass security restrictions to upload malicious PHP files, potentially leading to remote code execution (RCE).
Vulnerable Code
// admin/class-admin-settings.php line 571 public function check_filetype_and_ext( $info ) { $info['ext'] = 'json'; $info['type'] = 'application/json'; return $info; } --- // admin/class-admin-settings.php line 592 public function enable_json_upload( $file ) { if ( isset( $_POST['action'] ) && $_POST['action'] === 'wpuf_import_forms' ) { // @see wp_ajax_upload_attachment check_ajax_referer( 'media-form' ); add_filter( 'wp_check_filetype_and_ext', [ $this, 'check_filetype_and_ext' ] ); } return $file; }
Security Fix
@@ -563,12 +563,67 @@ * Allow json file to upload with async uploader * * @since 3.2.0 + * @since 4.2.9 Added security validation to prevent arbitrary file uploads * - * @param array $info + * @param array $info File data array with 'ext', 'type', and 'proper_filename' keys + * @param string $file Full path to the file + * @param string $filename The name of the file (may differ from $file due to $file being in a tmp directory) + * @param array $mimes Array of mime types keyed by their file extension regex + * @param string $real_mime The actual mime type or false if the type cannot be determined * * @return array */ - public function check_filetype_and_ext( $info ) { + public function check_filetype_and_ext( $info, $file, $filename, $mimes, $real_mime ) { + // Security: Validate this is actually a JSON file + + // 1. Check the file extension is .json + $filetype = wp_check_filetype( $filename, [ 'json' => 'application/json' ] ); + + if ( 'json' !== $filetype['ext'] ) { + // Not a .json file - reject it + return $info; + } + + // 2. Verify the file exists and is readable + if ( ! file_exists( $file ) || ! is_readable( $file ) ) { + return $info; + } + + // 3. Check for dangerous file extensions that might be disguised + $dangerous_extensions = [ 'php', 'php3', 'php4', 'php5', 'php7', 'phtml', 'phar', 'exe', 'sh', 'bat', 'cmd' ]; + $file_parts = pathinfo( $filename ); + + // Check for double extensions (e.g., shell.php.json) + $filename_lower = strtolower( $filename ); + foreach ( $dangerous_extensions as $ext ) { + if ( strpos( $filename_lower, '.' . $ext ) !== false ) { + // Dangerous extension found - reject + return $info; + } + } + + // 4. Validate the file content is actually valid JSON + $file_content = file_get_contents( $file ); + + if ( false === $file_content ) { + return $info; + } + + // Try to decode the JSON + json_decode( $file_content ); + + if ( json_last_error() !== JSON_ERROR_NONE ) { + // Not valid JSON - reject it + return $info; + } + + // 5. Additional security: Check file doesn't contain PHP tags + if ( preg_match( '/<\?php|<\?=|<script[^>]*>.*?<\/script>/i', $file_content ) ) { + // Contains PHP or script tags - reject it + return $info; + } + + // All validations passed - it's a legitimate JSON file $info['ext'] = 'json'; $info['type'] = 'application/json'; @@ -579,6 +634,7 @@ * Enable json file upload via ajax in tools page * * @since 3.2.0 + * @since 4.2.9 Added admin capability check for security * * @todo Move this method to WPUF_Admin_Tools class * @@ -597,7 +653,14 @@ ) { // @see wp_ajax_upload_attachment check_ajax_referer( 'media-form' ); - add_filter( 'wp_check_filetype_and_ext', [ $this, 'check_filetype_and_ext' ] ); + + // Security: Only allow admins to upload JSON files + if ( ! current_user_can( 'manage_options' ) ) { + $file['error'] = __( 'You do not have permission to upload files here.', 'wp-user-frontend' ); + return $file; + } + + add_filter( 'wp_check_filetype_and_ext', [ $this, 'check_filetype_and_ext' ], 10, 5 ); } return $file;
Exploit Outline
An authenticated user with Author privileges can exploit this vulnerability by targeting the plugin's form import AJAX action. 1. The attacker authenticates as an Author and accesses the 'Tools' page to obtain a valid nonce for the 'media-form' action (often exposed via localized scripts). 2. The attacker sends a multipart/form-data POST request to `/wp-admin/admin-ajax.php` with the parameter `action` set to `wpuf_import_forms`. 3. The request includes a malicious PHP file (e.g., `shell.php`) in the `import_file` field. 4. Because the vulnerable code blindly overrides the WordPress file validation metadata to claim the file is a JSON type, WordPress permits the upload and saves the file with its original name (or a slightly modified one, but still with the `.php` extension). 5. The attacker can then navigate to the uploaded file location in `/wp-content/uploads/YYYY/MM/shell.php` to execute arbitrary PHP code on the server.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.