Spin Wheel <= 2.1.0 - Unauthenticated Client-Side Prize Manipulation via 'prize_index' Parameter
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:NTechnical Details
<=2.1.0Source Code
WordPress.org SVN# 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) orspin_wheel_process_result(inferred). - Vulnerable Parameter:
prize_index(the integer representing the slice of the wheel). - Authentication: Unauthenticated (uses
wp_ajax_nopriv_hooks). - Preconditions:
- The plugin must be active.
- At least one "Spin Wheel" must be configured and active on a public page/post.
- A valid AJAX nonce is required for the request.
3. Code Flow (Inferred)
- Trigger: User clicks "Spin".
- Client-Side: JS function (e.g.,
spinWheel.calculateResult()) determines the segment. - 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' }); - Server-Side Handler: The function registered via
add_action('wp_ajax_nopriv_spin_wheel_claim_prize', ...)receives theprize_index. - 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.
- 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). - Setup Test Page:
wp post create --post_type=page --post_title="Spin to Win" --post_status=publish --post_content='[spin_wheel]' - Extract Nonce:
- Navigate to the newly created page.
- Look for the localized JS object. Common patterns:
spin_wheel_params,spin_wheel_ajax, orspin_wheel_data. - Use
browser_evalto 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:
(Note: Replaceaction=spin_wheel_claim_prize&prize_index=0&nonce=[EXTRACTED_NONCE]&email=attacker@example.comprize_index=0with the index of the most valuable prize).
6. Test Data Setup
- Install Plugin: Ensure
spin-wheelversion 2.1.0 is installed. - 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".
- 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
- Check Database: Use
wp evalorwp db queryto check if a coupon was generated or if the emailattacker@example.comis recorded as having won the prize associated withprize_index=0.wp option get spin_wheel_log # (inferred option name) - Compare Logic: Verify that regardless of how the wheel "looks" on the browser, sending
prize_index=0always results in the top prize, whileprize_index=5results in a loss.
9. Alternative Approaches
- Parameter Fuzzing: If
prize_indexis not the parameter name, search the JS files (public/js/spin-wheel.js) for$.ajaxorfetchcalls to identify the exact key used to transmit the result. - Client-Side Debugging: Use
browser_evalto 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_idorcampaign_idis required if multiple wheels exist.
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.