[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fxh9Q5bOBfqZiZisueFfHnJBjgbRH6zNN-niBNHPV6JI":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-42752","accept-stripe-payments-unauthenticated-payment-bypass","Accept Stripe Payments \u003C= 2.0.98 - Unauthenticated Payment Bypass","The Accept Stripe Payments plugin for WordPress is vulnerable to Payment Bypasses in all versions up to, and including, 2.0.98. This makes it possible for unauthenticated attackers to bypass payments.","stripe-payments",null,"\u003C=2.0.98","2.0.99","medium",5.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Authorization Bypass Through User-Controlled Key","2026-05-29 00:00:00","2026-06-02 11:19:40",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F8b932141-5adc-4ec2-9b4f-c6ba610de1b9?source=api-prod",4,[22,23,24,25,26,27,28,29],"accept-stripe-payments.php","includes\u002Fclass-asp-payment-data.php","includes\u002Fclass-asp-pp-ajax.php","includes\u002Fclass-asp-process-ipn-ng.php","includes\u002Fclass-asp-product-item.php","includes\u002Fclass-asp-utils-bot-mitigation.php","public\u002Fviews\u002Ftemplates\u002Fdefault\u002Fpayment-popup.php","readme.txt","researched",false,3,"# Research Plan: CVE-2026-42752 - Accept Stripe Payments Payment Bypass\n\n## 1. Vulnerability Summary\nThe **Accept Stripe Payments** plugin (\u003C= 2.0.98) is vulnerable to an unauthenticated payment bypass. The core issue resides in the handling of payment results in `ASP_Process_IPN_NG::handle_next_action_results`. The plugin allows a user-controlled parameter, `is_live`, to determine whether the transaction should be validated against Stripe's **Live** or **Test** API keys. \n\nAn attacker can complete a transaction using a test card via the plugin's test configuration and then force the server to validate that \"test\" payment as a successful purchase by setting `is_live=false` in the results handler, even for products intended for live production.\n\n## 2. Attack Vector Analysis\n*   **Endpoints:** \n    1.  `wp-admin\u002Fadmin-ajax.php?action=asp_pp_save_form_data` (Session Setup)\n    2.  `wp-admin\u002Fadmin-ajax.php?action=asp_next_action_results` (Bypass Trigger)\n*   **Vulnerable Parameter:** `is_live` (GET) and `payment_intent` (GET).\n*   **Authentication:** None required (`nopriv` AJAX actions).\n*   **Preconditions:**\n    *   A product must be created.\n    *   Stripe Test API keys must be configured in the plugin settings (often left in place after development or used for \"Sandbox\" mode).\n\n## 3. Code Flow\n1.  **Entry Point 1 (Session Setup):** The attacker calls `asp_pp_save_form_data`. The plugin saves product details (like `product_id`) into a server-side session transient (`asp_pp_form_data`).\n2.  **Entry Point 2 (The Bypass):** The attacker calls `asp_next_action_results`.\n3.  **Key Selection (`includes\u002Fclass-asp-process-ipn-ng.php`):**\n    ```php\n    $is_live = isset( $_GET['is_live'] ) ? sanitize_text_field( stripslashes ( $_GET['is_live'] ) ) : '';\n    $is_live = 'false' === $is_live ? 0 : 1;\n    \u002F\u002F ...\n    $key = $is_live ? $this->asp_class->APISecKey : $this->asp_class->APISecKeyTest;\n    \\Stripe\\Stripe::setApiKey( $key );\n    ```\n4.  **Verification:** The plugin retrieves the `payment_intent` using the selected `$key`. If the attacker provides a `payment_intent` created in the Stripe test environment and sets `is_live=false`, the retrieval succeeds.\n5.  **Fulfillment:** The plugin calls `process_ipn()`, which validates the amount and fulfills the order (e.g., provides download links or marks the order as paid).\n\n## 4. Nonce Acquisition Strategy\nThe action `asp_pp_save_form_data` is used to initialize the session. While its implementation is not fully shown, it is likely authenticated by `asp_pp_ajax_nonce`.\n\n1.  **Identify Shortcode:** The plugin uses `[asp_product id=\"ID\"]` to display products.\n2.  **Create Page:** Create a test page containing the product shortcode.\n3.  **Extract Nonce:** \n    *   Navigate to the product page.\n    *   The nonce and other metadata are localized via `wp_localize_script`.\n    *   In the source of `public\u002Fviews\u002Ftemplates\u002Fdefault\u002Fpayment-popup.php`, variables are printed into the global scope.\n    *   Use `browser_eval` to find the nonce: `browser_eval(\"window.stripe_payments_vars?.nonce\")` or check for `asp_pp_ajax_nonce` in the script tags.\n\n## 5. Exploitation Strategy\n\n### Step 1: Session Setup\nCall `asp_pp_save_form_data` to associate the current session with the target product.\n*   **URL:** `http:\u002F\u002Fvulnerable-test.local\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Method:** POST\n*   **Payload (application\u002Fx-www-form-urlencoded):**\n    *   `action`: `asp_pp_save_form_data`\n    *   `nonce`: `[EXTRACTED_NONCE]`\n    *   `asp_product_id`: `[TARGET_PRODUCT_ID]`\n\n### Step 2: Bypass Trigger\nInvoke the results handler with `is_live=false` and a test `payment_intent`.\n*   **URL:** `http:\u002F\u002Fvulnerable-test.local\u002Fwp-admin\u002Fadmin-ajax.php?action=asp_next_action_results&is_live=false&payment_intent=[TEST_PI_ID]`\n*   **Method:** GET\n*   **Note:** In a real-world scenario, `[TEST_PI_ID]` is obtained by completing a checkout using Stripe's test card (e.g., `4242...`) against the site's public test key. For a PoC in an isolated environment, if Stripe API connectivity is unavailable, the goal is to demonstrate that the code switches to `APISecKeyTest` based on the GET parameter.\n\n## 6. Test Data Setup\n1.  **Configure Plugin:**\n    ```bash\n    # Set dummy Stripe keys\n    wp option update AcceptStripePayments-settings '{\"api_key_test_public\":\"pk_test_dummy\",\"api_key_test_secret\":\"sk_test_dummy\",\"api_key_live_public\":\"pk_live_dummy\",\"api_key_live_secret\":\"sk_live_dummy\"}' --format=json\n    ```\n2.  **Create Product:**\n    ```bash\n    wp post create --post_type=asp-products --post_title=\"Expensive Digital Asset\" --post_status=publish\n    # Capture the generated Product ID\n    ```\n3.  **Place Shortcode:**\n    ```bash\n    wp post create --post_type=page --post_title=\"Store\" --post_content='[asp_product id=\"[ID]\"]' --post_status=publish\n    ```\n\n## 7. Expected Results\n*   The `asp_next_action_results` call should trigger `process_ipn`.\n*   The plugin should redirect to the \"Thank You\" page (`checkout_url` setting).\n*   The plugin's debug log (if enabled via `ASP_Debug_Logger`) should show \"Payment processing started\" using the test key despite the product potentially being live.\n\n## 8. Verification Steps\nAfter the HTTP requests, verify the order creation via WP-CLI:\n```bash\n# Check for new orders (post_type: stripe_order)\nwp post list --post_type=stripe_order --orderby=post_date --order=DESC\n```\nThe order status should be marked as complete\u002Fpaid even though no real funds were transferred.\n\n## 9. Alternative Approaches\nIf `asp_pp_save_form_data` is strictly nonced or session-locked, examine the `wp_loaded` entry point in `includes\u002Fclass-asp-process-ipn-ng.php`:\n```php\n$process_ipn = filter_input( INPUT_POST, 'asp_process_ipn', FILTER_SANITIZE_NUMBER_INT );\nif ( $process_ipn ) {\n    add_action( 'wp_loaded', array( $this, 'process_ipn' ), 2147483647 );\n}\n```\nThis path directly hits `process_ipn()` without the AJAX wrapper, potentially allowing an attacker to bypass the `is_live` check entirely if they can inject POST data that `process_ipn` trusts. Check if `process_ipn` verifies the `payment_intent` independently of the `is_live` logic used in the AJAX handler.","The Accept Stripe Payments plugin for WordPress is vulnerable to an unauthenticated payment bypass due to the use of a user-controlled parameter to select the Stripe API environment (Live vs. Test). An attacker can submit a Stripe test-mode payment intent and force the plugin to validate it against test credentials by setting 'is_live=false', resulting in order fulfillment for live products without actual payment.","\u002F\u002F includes\u002Fclass-asp-process-ipn-ng.php line 64\n\t\t$pi_id = isset( $_GET['payment_intent'] ) ? sanitize_text_field( stripslashes ( $_GET['payment_intent'] ) ) : '';\n\n\t\t$is_live = isset( $_GET['is_live'] ) ? sanitize_text_field( stripslashes ( $_GET['is_live'] ) ) : '';\n\t\t$is_live = 'false' === $is_live ? 0 : 1;\n\n---\n\n\u002F\u002F includes\u002Fclass-asp-process-ipn-ng.php line 81\n\t\ttry {\n\n\t\t\tASPMain::load_stripe_lib();\n\t\t\t$key = $is_live ? $this->asp_class->APISecKey : $this->asp_class->APISecKeyTest;\n\t\t\t\\Stripe\\Stripe::setApiKey( $key );","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Faccept-stripe-payments.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Faccept-stripe-payments.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Faccept-stripe-payments.php\t2026-04-19 11:04:22.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Faccept-stripe-payments.php\t2026-05-07 03:52:06.000000000 +0000\n@@ -3,7 +3,7 @@\n \u002F**\n  * Plugin Name: Accept Stripe Payments\n  * Description: Easily accept credit card payments via Stripe payment gateway in WordPress.\n- * Version: 2.0.98\n+ * Version: 2.0.99\n  * Author: Tips and Tricks HQ, wptipsntricks\n  * Author URI: https:\u002F\u002Fwww.tipsandtricks-hq.com\u002F\n  * Plugin URI: https:\u002F\u002Fs-plugins.com\n@@ -19,7 +19,7 @@\n \texit; \n }\n \n-define( 'WP_ASP_PLUGIN_VERSION', '2.0.98' );\n+define( 'WP_ASP_PLUGIN_VERSION', '2.0.99' );\n define( 'WP_ASP_MIN_PHP_VERSION', '7.4' );\n define( 'WP_ASP_PLUGIN_URL', plugins_url( '', __FILE__ ) );\n define( 'WP_ASP_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fincludes\u002Fclass-asp-payment-data.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fincludes\u002Fclass-asp-payment-data.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fincludes\u002Fclass-asp-payment-data.php\t2025-08-16 09:48:08.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fincludes\u002Fclass-asp-payment-data.php\t2026-05-07 03:52:06.000000000 +0000\n@@ -264,6 +264,11 @@\n \n \t\t$this->billing_details_obj = $bd;\n \n+\t\t$cd = new stdClass;\n+\t\t$cd->name = $b_name;\n+\t\t$cd->email = $b_email;\n+\t\t$this->customer_obj = $cd;\n+\n \t\t\u002F\u002FShipping details\n \t\t$same_addr = $ipn_ng_class->get_post_var( 'asp_same-bill-ship-addr' );\n \ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fincludes\u002Fclass-asp-pp-ajax.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fincludes\u002Fclass-asp-pp-ajax.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fincludes\u002Fclass-asp-pp-ajax.php\t2025-08-16 09:48:08.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fincludes\u002Fclass-asp-pp-ajax.php\t2026-05-07 03:52:06.000000000 +0000\n@@ -700,6 +700,9 @@\n \t\t$zero_value_id           = str_replace( '.', '', uniqid( 'free_', true ) );\n \t\t$coupon['zero_value_id'] = $zero_value_id;\n \n+        \u002F\u002F Saving applied coupon signature data so that it can be verified later.\n+\t\tASP_Utils_Bot_Mitigation::record_full_discount_signature_data($product_id, $coupon_code, $zero_value_id);\n+\n \t\twp_send_json( $coupon );\n \n \t}\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fincludes\u002Fclass-asp-process-ipn-ng.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fincludes\u002Fclass-asp-process-ipn-ng.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fincludes\u002Fclass-asp-process-ipn-ng.php\t2026-04-19 11:04:22.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fincludes\u002Fclass-asp-process-ipn-ng.php\t2026-05-07 03:52:06.000000000 +0000\n@@ -215,6 +215,12 @@\n \t\t\t\u002F\u002FASP_Debug_Logger::log( 'Original $_POST data: ' . $post_data_str );\n \t\t}\n \n+\t\t$nonce = $this->get_post_var( 'asp_payment_form_nonce' );\n+\t\tif (empty($nonce) || !wp_verify_nonce($nonce, 'asp_payment_form_nonce')){\n+\t\t\t\u002F\u002F ASP_Debug_Logger::log( 'Nonce verification failed!', false);\n+\t\t\twp_die( __('Nonce verification failed!', 'stripe-payments') );\n+\t\t}\n+\n \t\tdo_action( 'asp_ng_before_payment_processing', $post_data );\n \n \t\t$this->sess = ASP_Session::get_instance();\n@@ -812,6 +818,14 @@\n \t\t\t\u002F\u002Fthis is zero-value transaction\n \t\t\t$coupon_code = $this->get_post_var( 'asp_coupon-code' );\n \t\t\t$coupon_code = sanitize_text_field( stripslashes( $coupon_code ));\n+\t\t\t$prod_id = $this->item->get_product_id();\n+\n+\t\t\t\u002F\u002F Check coupon signature data\n+\t\t\tif( empty(ASP_Utils_Bot_Mitigation::is_full_discount_signature_data_valid($prod_id, $coupon_code, $pi)) ){\n+\t\t\t\t\u002F\u002F Signature is invalid.\n+\t\t\t\twp_die(sprintf(__( \"Error! Invalid transaction ID: %s\", 'stripe-payments' ), $pi));\n+\t\t\t}\n+\n \t\t\tif ( empty( $coupon_code ) ) {\n \t\t\t\treturn $p_data;\n \t\t\t}\n@@ -829,8 +843,6 @@\n \t\t\t\treturn $p_data;\n \t\t\t}\n \n-\t\t\t$prod_id = $this->item->get_product_id();\n-\n \t\t\t$order = new ASP_Order_Item();\n \n \t\t\tif ( $order->can_create( $prod_id ) ) {\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fincludes\u002Fclass-asp-product-item.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fincludes\u002Fclass-asp-product-item.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fincludes\u002Fclass-asp-product-item.php\t2025-12-01 09:38:00.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fincludes\u002Fclass-asp-product-item.php\t2026-05-07 03:52:06.000000000 +0000\n@@ -535,6 +535,18 @@\n \t\tif ( ! $this->coupon ) {\n \t\t\treturn false;\n \t\t}\n+\n+\t\t\u002F\u002F First check if coupon option is enabled for this product. (the settings in edit product page)\n+\t\t$coupons_enabled_for_product = get_post_meta( $this->post_id, 'asp_product_coupons_setting', true );\n+\t\tif ( $coupons_enabled_for_product === '' || $coupons_enabled_for_product == '2') {\n+\t\t\t$coupons_enabled_for_product = $this->asp_main->get_setting( 'coupons_enabled' );\n+\t\t}\n+\t\tif ( empty( $coupons_enabled_for_product ) ){\n+\t\t\t$this->last_error = __( 'Applying coupon is not allowed for this product.', 'stripe-payments' );\n+\t\t\t$this->coupon = false;\n+\t\t\treturn false;\n+\t\t}\n+\n \t\t\u002F\u002Fcheck if coupon is allowed for the product\n \t\t$only_for_allowed_products = get_post_meta( $this->coupon['id'], 'asp_coupon_only_for_allowed_products', true );\n \t\tif ( $only_for_allowed_products ) {\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fincludes\u002Fclass-asp-utils-bot-mitigation.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fincludes\u002Fclass-asp-utils-bot-mitigation.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fincludes\u002Fclass-asp-utils-bot-mitigation.php\t2025-08-16 09:48:08.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fincludes\u002Fclass-asp-utils-bot-mitigation.php\t2026-05-07 03:52:06.000000000 +0000\n@@ -140,7 +140,81 @@\n         \n         return true;\n     }\n-    \n+\n+\tpublic static function get_full_discount_signature_data() {\n+\t\t$full_discount_signature_arr = get_transient('asp_full_discount_signature');\n+\t\tif (!isset($full_discount_signature_arr) || empty($full_discount_signature_arr)) {\n+\t\t\t$full_discount_signature_arr = array();\n+\t\t}\n+\t\treturn $full_discount_signature_arr;\n+\t}\n+\n+\tpublic static function record_full_discount_signature_data($product_id, $coupon_code, $txn_id) {\n+\t\t$ip_address = ASP_Utils::get_user_ip_address();\n+\t\t\u002F\u002F$current_wp_time = current_time('mysql');\n+\n+\t\tif (!isset($ip_address) || empty($ip_address)) {\n+\t\t\tASP_Debug_Logger::log('IP address value missing (could not read the IP address of the user). Cannot record this full discount signature. The extra security check later may fail.', false);\n+\t\t\treturn;\n+\t\t}\n+\n+\t\t$full_discount_signature_arr = ASP_Utils_Bot_Mitigation::get_full_discount_signature_data();\n+\n+\t\t$hp_key = ASP_Utils_Bot_Mitigation::get_asp_hash_private_key_one();\n+\n+\t\t$index = $product_id. '_' .$ip_address. '_' .$txn_id;\n+\t\t$signature = sha1($hp_key.$product_id.$coupon_code.$ip_address.$txn_id);\n+\t\t$full_discount_signature_arr[$index] = $signature;\n+\n+\t\t\u002F\u002F TODO: Debug Purpose Only.\n+\t\t\u002F\u002FASP_Debug_Logger::log('Index: ' . $index . ', Signature: ' . $signature . ', IP Address: ' . $ip_address . ' Txn ID: '. $txn_id);\n+\t\t\u002F\u002FASP_Debug_Logger::log_array_data($full_discount_signature_arr);\n+\n+\t\t\u002F\u002FSave the page load signature data with an expiry of 1 hour.\n+\t\tset_transient('asp_full_discount_signature', $full_discount_signature_arr, 3600);\n+\t}\n+\n+\tpublic static function is_full_discount_signature_data_valid($product_id, $coupon_code, $txn_id) {\n+\t\t$full_discount_signature_arr = get_transient('asp_full_discount_signature');\n+\t\tif (!isset($full_discount_signature_arr) || empty($full_discount_signature_arr)) {\n+\t\t\tASP_Debug_Logger::log( 'Full discount signature check - currently there are no entries in the saved data for full discount signature.', false );\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\t$ip_address_to_check = ASP_Utils::get_user_ip_address();\n+\t\tif (!isset($ip_address_to_check) || empty($ip_address_to_check)) {\n+\t\t\tASP_Debug_Logger::log( 'Full discount signature check - IP address value for this request is missing.', false );\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\t$index = $product_id. '_'.$ip_address_to_check. '_' .$txn_id;\n+\n+\t\tif (!isset($full_discount_signature_arr[$index]) || empty ($full_discount_signature_arr[$index])){\n+\t\t\tASP_Debug_Logger::log( 'Full discount check - cannot find this Product ID and IP address index ('.$index.') in the saved data.', false );\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\t$hp_key = ASP_Utils_Bot_Mitigation::get_asp_hash_private_key_one();\n+\n+\t\t$expected_signature = $full_discount_signature_arr[$index];\n+\t\t$received = sha1($hp_key.$product_id.$coupon_code.$ip_address_to_check.$txn_id);\n+\n+\t\t\u002F\u002F TODO: Debug Purpose Only.\n+\t\t\u002F\u002FASP_Debug_Logger::log('Index: ' . $index . ', Signature Received: ' . $received . ', Expected: ' . $expected_signature, true);\n+\t\t\u002F\u002FASP_Debug_Logger::log_array_data($full_discount_signature_arr);\n+\n+\t\tif (!hash_equals($expected_signature, $received)){\n+\t\t\t\u002F\u002FMis-match\n+\t\t\tASP_Debug_Logger::log( 'Full discount check - the signature hash does not match.', false );\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\t\u002F\u002FEntry for the received signature exists\n+\t\tASP_Debug_Logger::log( 'Full discount check done!' );\n+\n+\t\treturn true;\n+\t}\n+\n     public static function get_request_limit_count_data() {\n         $asp_request_usage_count = get_transient('asp_request_usage_count');\n         if (!isset($asp_request_usage_count) || empty($asp_request_usage_count)) {\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fpublic\u002Fviews\u002Ftemplates\u002Fdefault\u002Fpayment-popup.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fpublic\u002Fviews\u002Ftemplates\u002Fdefault\u002Fpayment-popup.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Fpublic\u002Fviews\u002Ftemplates\u002Fdefault\u002Fpayment-popup.php\t2025-08-16 09:48:08.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Fpublic\u002Fviews\u002Ftemplates\u002Fdefault\u002Fpayment-popup.php\t2026-05-07 03:52:06.000000000 +0000\n@@ -513,6 +513,7 @@\n \t\t\t\t\t\t\u003Cinput type=\"hidden\" id=\"btn-uniq-id\" name=\"btn_uniq_id\" value=\"\u003C?php echo ! empty( $a['btn_uniq_id'] ) ? esc_attr( $a['btn_uniq_id'] ) : ''; ?>\">\n \t\t\t\t\t\t\u003Cinput type=\"hidden\" id=\"product-id\" name=\"product_id\" value=\"\u003C?php echo esc_attr( $a['prod_id'] ); ?>\">\n \t\t\t\t\t\t\u003Cinput type=\"hidden\" name=\"process_ipn\" value=\"1\">\n+                        \u003Cinput type=\"hidden\" value=\"\u003C?php echo esc_attr(wp_create_nonce('asp_payment_form_nonce')) ?>\" name=\"payment_form_nonce\">\n \t\t\t\t\t\t\u003Cinput type=\"hidden\" name=\"is_live\" value=\"\u003C?php echo $a['is_live'] ? '1' : '0'; ?>\">\n \t\t\t\t\t\t\u003C?php if ( $a['data']['url'] ) { ?>\n \t\t\t\t\t\t\u003Cinput type=\"hidden\" name=\"item_url\" value=\"\u003C?php echo esc_attr( $a['data']['url'] ); ?>\">\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Freadme.txt \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Freadme.txt\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.98\u002Freadme.txt\t2026-04-19 11:04:22.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fstripe-payments\u002F2.0.99\u002Freadme.txt\t2026-05-07 03:52:06.000000000 +0000\n@@ -5,7 +5,7 @@\n Requires at least: 6.0\n Tested up to: 7.0\n Requires PHP: 7.4\n-Stable tag: 2.0.98\n+Stable tag: 2.0.99\n License: GPLv2 or later\n License URI: http:\u002F\u002Fwww.gnu.org\u002Flicenses\u002Fgpl-2.0.html\n \n@@ -157,6 +157,12 @@\n \n == Changelog ==\n \n+= 2.0.99 =\n+- Added a server-side check to verify that the coupon feature is enabled before attempting to apply a coupon code.\n+- Added an additional verification check for 100% discount coupons.\n+- Added nonce verification to the form submission process.\n+- Fixed a minor PHP warning on the checkout result page during 100% discount checkout scenarios.\n+\n = 2.0.98 =\n - Added prefixes to the Gutenberg block variables to prevent potential conflicts with other plugins.\n - Added new filter hook 'asp_process_ipn_order_status' to allow modification of the order status before changing the order status in the IPN processing code.","The exploit involves two main steps: session initialization and payment environment manipulation. First, an unauthenticated attacker calls the 'asp_pp_save_form_data' AJAX endpoint to associate their session with a specific target product ID. Second, the attacker generates a legitimate Stripe Payment Intent using a test-mode credit card (against the site's public test key). Finally, the attacker triggers the 'asp_next_action_results' endpoint while passing 'is_live=false' and the test payment intent ID. Because the plugin uses the 'is_live' parameter to determine which secret key to use for server-side verification, it validates the test-mode intent against the plugin's test credentials and proceeds to fulfill the order for the live product.","gemini-3-flash-preview","2026-06-04 15:16:44","2026-06-04 15:18:24",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","2.0.98","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fstripe-payments\u002Ftags\u002F2.0.98","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fstripe-payments.2.0.98.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fstripe-payments\u002Ftags\u002F2.0.99","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fstripe-payments.2.0.99.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fstripe-payments\u002Ftags"]