CVE-2026-1565

User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration <= 4.2.8 - Authenticated (Author+) Arbitrary File Upload

highUnrestricted Upload of File with Dangerous Type
8.8
CVSS Score
8.8
CVSS Score
high
Severity
4.2.9
Patched in
1d
Time to patch

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:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=4.2.8
PublishedFebruary 26, 2026
Last updatedFebruary 26, 2026
Affected pluginwp-user-frontend

What Changed in the Fix

Changes introduced in v4.2.9

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

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_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 in admin/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_role might 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

  1. Entry Point: The attacker sends a POST request to admin-ajax.php with action=wpuf_import_forms.
  2. Handler: WPUF_Admin_Settings::import_forms() is invoked.
  3. Upload Trigger: Inside import_forms(), the plugin calls wp_handle_upload() to process $_FILES['import_file'].
  4. Vulnerable Filter: During wp_handle_upload(), WordPress triggers the wp_check_filetype_and_ext filter. The plugin has registered WPUF_Admin_Settings::check_filetype_and_ext() (or Admin_Tools::check_filetype_and_ext) to this filter.
  5. 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 .json anywhere 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 .php file as a valid .json upload.
  6. Persistence: wp_handle_upload() moves the file to the wp-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.

  1. Identify Location: The tools page is at wp-admin/admin.php?page=wpuf_tools.
  2. Navigate: Use browser_navigate to access the Tools page as an Author-level user.
  3. Extract Nonce: The nonce is likely localized via wp_localize_script. Search for script tags containing wpuf_admin or wpuf_tools objects.
    • Candidate JS Variable: window.wpuf_admin or window.wpuf_import_nonce.
    • Execution:
      // Example guess based on common WPUF patterns
      browser_eval("window.wpuf_admin?.nonce || document.querySelector('#wpuf_import_forms_nonce')?.value")
      
  4. Verification: If no nonce check is found in the import_forms function (via manual inspection of the admin/class-admin-settings.php full source), the check may be missing entirely.

5. Exploitation Strategy

  1. Preparation: Prepare a PHP shell payload named exploit.php.
  2. Alternative Filename: If the filter specifically looks for .json, use exploit.php.json. If the filter is flawed, it will allow the upload and keep the .php extension in the final path or allow a double extension.
  3. 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)
  4. Execution: Send the request using http_request.
  5. Path Discovery: The response from wp_ajax_wpuf_import_forms usually returns the result of the import. If it fails due to invalid JSON, look for the file path in the wp-content/uploads/ directory for the current year/month.

6. Test Data Setup

  1. Create Author User:
    wp user create attacker attacker@example.com --role=author --user_pass=password
    
  2. 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
    
  3. 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.php executes the PHP code.

8. Verification Steps

  1. Check Filesystem:
    find /var/www/html/wp-content/uploads/ -name "exploit.php"
    
  2. Test Execution: Use http_request to GET the uploaded file and check for the payload's output (e.g., uid=... if id command was used).

9. Alternative Approaches

  • Double Extension: Try exploit.json.php or exploit.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/json in the multipart part for the PHP file to trick the check_filetype_and_ext logic if it relies on the browser-provided MIME type.
Research Findings
Static analysis — not yet PoC-verified

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

--- /home/deploy/wp-safety.org/data/plugin-versions/wp-user-frontend/4.2.8/admin/class-admin-settings.php	2025-10-30 11:48:36.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-user-frontend/4.2.9/admin/class-admin-settings.php	2026-02-24 08:47:32.000000000 +0000
@@ -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.