CVE-2026-0808

Spin Wheel <= 2.1.0 - Unauthenticated Client-Side Prize Manipulation via 'prize_index' Parameter

mediumClient-Side Enforcement of Server-Side Security
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
2.1.1
Patched in
1d
Time to patch

Description

The Spin Wheel plugin for WordPress is vulnerable to client-side prize manipulation in all versions up to, and including, 2.1.0. This is due to the plugin trusting client-supplied prize selection data without server-side validation or randomization. This makes it possible for unauthenticated attackers to manipulate which prize they win by modifying the 'prize_index' parameter sent to the server, allowing them to always select the most valuable prizes.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.1.0
PublishedJanuary 16, 2026
Last updatedJanuary 17, 2026
Affected pluginspin-wheel

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-0808 (Spin Wheel Prize Manipulation) ## 1. Vulnerability Summary The **Spin Wheel** plugin (versions <= 2.1.0) suffers from a critical logic flaw where the prize selection process is performed client-side and trusted implicitly by the server. When a user spins…

Show full research plan

Exploitation Research Plan: CVE-2026-0808 (Spin Wheel Prize Manipulation)

1. Vulnerability Summary

The Spin Wheel plugin (versions <= 2.1.0) suffers from a critical logic flaw where the prize selection process is performed client-side and trusted implicitly by the server. When a user spins the wheel, the JavaScript code calculates the winning segment and sends the resulting index to the server via an AJAX request. The server-side handler accepts this prize_index without verifying if the result was determined by a secure server-side randomizer, allowing an attacker to bypass the intended "game of chance" and claim any prize (e.g., the highest value discount coupon) by sending a forged request.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: spin_wheel_claim_prize (inferred) or spin_wheel_process_result (inferred).
  • Vulnerable Parameter: prize_index (the integer representing the slice of the wheel).
  • Authentication: Unauthenticated (uses wp_ajax_nopriv_ hooks).
  • Preconditions:
    1. The plugin must be active.
    2. At least one "Spin Wheel" must be configured and active on a public page/post.
    3. A valid AJAX nonce is required for the request.

3. Code Flow (Inferred)

  1. Trigger: User clicks "Spin".
  2. Client-Side: JS function (e.g., spinWheel.calculateResult()) determines the segment.
  3. AJAX Call: JS sends a POST request:
    jQuery.post(spin_wheel_vars.ajax_url, {
        action: 'spin_wheel_claim_prize',
        prize_index: 3, // Attacker changes this value
        nonce: spin_wheel_vars.nonce,
        email: 'user@example.com'
    });
    
  4. Server-Side Handler: The function registered via add_action('wp_ajax_nopriv_spin_wheel_claim_prize', ...) receives the prize_index.
  5. Sink: The handler retrieves the prize details from the plugin's settings using the provided index:
    $prizes = get_option('spin_wheel_prizes');
    $won_prize = $prizes[$_POST['prize_index']];
    // Server generates/sends coupon for $won_prize without checking logic.
    

4. Nonce Acquisition Strategy

The plugin likely enqueues its scripts and localizes a nonce for the AJAX action on pages containing the wheel.

  1. Identify Entry Point: Search for the shortcode registration in the plugin files:
    grep -r "add_shortcode" wp-content/plugins/spin-wheel/
    Likely Shortcode: [spin_wheel] (inferred).
  2. Setup Test Page:
    wp post create --post_type=page --post_title="Spin to Win" --post_status=publish --post_content='[spin_wheel]'
    
  3. Extract Nonce:
    • Navigate to the newly created page.
    • Look for the localized JS object. Common patterns: spin_wheel_params, spin_wheel_ajax, or spin_wheel_data.
    • Use browser_eval to extract the nonce:
      browser_eval("window.spin_wheel_vars?.nonce") (inferred identifier).

5. Exploitation Strategy

Step 1: Identify Target Prize Index

First, inspect the plugin settings or the frontend wheel structure to determine which prize_index corresponds to the most valuable reward (e.g., Index 0 is often the "Grand Prize").

Step 2: Forge the Reward Claim

Send a direct POST request to admin-ajax.php.

HTTP Request (via http_request tool):

  • Method: POST
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Headers:
    • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=spin_wheel_claim_prize&prize_index=0&nonce=[EXTRACTED_NONCE]&email=attacker@example.com
    
    (Note: Replace prize_index=0 with the index of the most valuable prize).

6. Test Data Setup

  1. Install Plugin: Ensure spin-wheel version 2.1.0 is installed.
  2. Configure Prizes:
    • Use WP-CLI or the admin panel to ensure "Prize 0" is a "50% Discount" and "Prize 5" is "Better luck next time".
  3. Publish Wheel: Create a page with the shortcode as described in Section 4.

7. Expected Results

  • Success: The server responds with a JSON success message, e.g., {"success":true,"data":{"coupon_code":"SAVE50","message":"Congratulations!"}}.
  • Impact: The attacker receives a high-value coupon code that they should not have been able to "win" deterministically.

8. Verification Steps

  1. Check Database: Use wp eval or wp db query to check if a coupon was generated or if the email attacker@example.com is recorded as having won the prize associated with prize_index=0.
    wp option get spin_wheel_log # (inferred option name)
    
  2. Compare Logic: Verify that regardless of how the wheel "looks" on the browser, sending prize_index=0 always results in the top prize, while prize_index=5 results in a loss.

9. Alternative Approaches

  • Parameter Fuzzing: If prize_index is not the parameter name, search the JS files (public/js/spin-wheel.js) for $.ajax or fetch calls to identify the exact key used to transmit the result.
  • Client-Side Debugging: Use browser_eval to trigger the actual spin function but overwrite the variable that stores the result just before the AJAX call is fired.
  • ID Manipulation: Check if a wheel_id or campaign_id is required if multiple wheels exist.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Spin Wheel plugin for WordPress (<= 2.1.0) is vulnerable to client-side prize manipulation because it determines the winning segment on the client side and trusts the result transmitted to the server. An unauthenticated attacker can supply a manipulated 'prize_index' via an AJAX request to claim any prize, effectively bypassing the intended random selection process.

Exploit Outline

1. Access a public-facing page where the Spin Wheel shortcode is active. 2. Inspect the page source or localized JavaScript objects (such as 'spin_wheel_vars') to retrieve the AJAX nonce and the WordPress AJAX URL (admin-ajax.php). 3. Determine the 'prize_index' corresponding to the most valuable reward (e.g., Index 0 for a grand prize) by examining the wheel configuration. 4. Send a POST request to '/wp-admin/admin-ajax.php' using the identified AJAX action (such as 'spin_wheel_claim_prize'), including the valid nonce, the attacker's email address, and the target 'prize_index'. 5. The server-side handler accepts the client-provided index without server-side randomization or verification, allowing the attacker to claim the specified reward.

Check if your site is affected.

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