Subscription & Recurring Payment for WooCommerce <= 1.9.1 - Cross-Site Request Forgery
Description
The Subscription & Recurring Payment for WooCommerce plugin for WordPress is vulnerable to Cross-Site Request Forgery in versions up to, and including, 1.9.1. This is due to missing or incorrect nonce validation on a function. This makes it possible for unauthenticated attackers to perform an unauthorized action via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v1.9.2
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-24554 (CSRF in Subscription & Recurring Payment for WooCommerce) ## 1. Vulnerability Summary The **Subscription & Recurring Payment for WooCommerce** plugin (versions <= 1.9.1) contains multiple Cross-Site Request Forgery (CSRF) vulnerabilities. The primary fl…
Show full research plan
Exploitation Research Plan: CVE-2026-24554 (CSRF in Subscription & Recurring Payment for WooCommerce)
1. Vulnerability Summary
The Subscription & Recurring Payment for WooCommerce plugin (versions <= 1.9.1) contains multiple Cross-Site Request Forgery (CSRF) vulnerabilities. The primary flaw resides in the lack of (or incorrect) nonce validation in the AJAX handler for bulk subscription actions and potentially in the plugin installer endpoints. This allows an unauthenticated attacker to trick a logged-in administrator into performing destructive actions, such as permanently deleting subscriptions or modifying plugin states, by visiting a malicious link or form.
2. Attack Vector Analysis
- Vulnerable AJAX Action:
wp_subscription_bulk_action - Vulnerable Installer Actions:
install_woocommerce_pluginandwps_subscription_activate_woocommerce_plugin - Endpoint:
/wp-admin/admin-ajax.php - Required Authentication: Admin-level (triggered via the victim's session).
- HTTP Method:
POST - Preconditions:
- The victim must be a logged-in administrator.
- At least one subscription must exist on the site for the bulk action exploit.
3. Code Flow
- Entry Point: The plugin registers AJAX handlers in
includes/Admin/Menu.phpand (likely) an installer file:// includes/Admin/Menu.php add_action( 'wp_ajax_wp_subscription_bulk_action', array( $this, 'handle_bulk_action_ajax' ) ); - AJAX Call (JS side): In
assets/js/admin.js, thehandleBulkActionfunction sends a POST request:jQuery.ajax({ url: wp_subscription_ajax.ajaxurl, type: "POST", data: { action: "wp_subscription_bulk_action", bulk_action: action, // e.g., "delete" subscription_ids: subscriptionIds, nonce: wp_subscription_ajax.nonce, }, // ... }); - Vulnerable Sink: The PHP function
handle_bulk_action_ajax(referenced inMenu.php) processes thebulk_action(delete, trash, etc.) for the providedsubscription_ids. The vulnerability exists because this function either omitscheck_ajax_refererentirely or performs an "incorrect" check (e.g., checking for a parameter that doesn't exist or failing to terminate execution on failure).
4. Nonce Acquisition Strategy
The vulnerability is CSRF. If the handler completely lacks a nonce check, no acquisition is required. However, the description mentions "incorrect" validation. If the check is conditional (e.g., if (isset($_POST['nonce'])) { wp_verify_nonce(...) }), the exploit simply omits the nonce.
If a nonce is required but can be leaked (e.g., to an unauthenticated user):
- Identify Script Loading: The
sdevs_subscription_adminscript (and its localized nonce) is enqueued on thewp-subscriptionadmin page. - Page Creation: Create a page that might trigger the plugin logic (though these are admin-only scripts, sometimes they leak into the frontend via shared helpers).
- Extraction:
- Use
browser_navigateto the Admin Subscription list:/wp-admin/admin.php?page=wp-subscription. - Use
browser_evalto extract the nonce:window.wp_subscription_ajax?.nonce. - Note: For standard CSRF PoCs, we demonstrate that the action executes without a valid nonce to prove the vulnerability.
- Use
5. Exploitation Strategy
Scenario: Bulk Deletion of Subscriptions
- Target Action:
wp_subscription_bulk_action - Action Parameter:
bulk_action=delete - Payload Formulation:
action=wp_subscription_bulk_action bulk_action=delete subscription_ids[]=1 subscription_ids[]=2 - Execution: Use the
http_requesttool to simulate the admin's browser performing the POST request without a nonce (or with an invalid one).
HTTP Request Payload (via http_request)
- URL:
http://[target-ip]/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=wp_subscription_bulk_action&bulk_action=delete&subscription_ids[]=1
6. Test Data Setup
- Create Subscriptions: Since subscriptions are often Custom Post Types or custom table entries, the easiest way is to use the plugin's UI to create a test subscription or use WP-CLI if the post type is known.
- Assumption: Subscriptions are stored as post type
subscrpt_order(based on internal naming). wp post create --post_type=subscrpt_order --post_status=publish --post_title="Test Subscription"
- Assumption: Subscriptions are stored as post type
- Identify IDs: Get the ID of the created subscription:
wp post list --post_type=subscrpt_order
7. Expected Results
- Response: The AJAX handler should return a JSON success message:
{"success":true,"data":{"message":"..."}}. - Side Effect: The subscription with the specified ID should be permanently removed from the database.
8. Verification Steps
- Post-Exploit Check: Attempt to retrieve the subscription via WP-CLI:
wp post get [ID]
- Success Criteria: If the command returns "Could not find the post," the deletion via CSRF was successful.
- Database Check:
wp db query "SELECT count(*) FROM wp_posts WHERE post_type='subscrpt_order'"(Count should decrease).
9. Alternative Approaches
Installer CSRF
If bulk actions are protected, target the installer endpoints found in assets/js/installer.js:
- Action:
install_woocommerce_plugin - Body:
action=install_woocommerce_plugin&install_plugin=woocommerce - Action:
wps_subscription_activate_woocommerce_plugin - Body:
action=wps_subscription_activate_woocommerce_plugin&activate_plugin=woocommerce
Verify if these actions can be triggered by an admin session without a nonce, which could be used to disrupt the site or force-install specific plugins.
Summary
The Subscription & Recurring Payment for WooCommerce plugin is vulnerable to Cross-Site Request Forgery (CSRF) because it lacks nonce validation on several AJAX endpoints, specifically those handling bulk subscription actions and plugin installation. This allows unauthenticated attackers to trick a logged-in administrator into performing unauthorized actions, such as deleting subscriptions or installing/activating the WooCommerce plugin, by visiting a malicious link or submitting a forged form.
Vulnerable Code
// includes/Admin/Menu.php line 18 add_action( 'wp_ajax_wp_subscription_bulk_action', array( $this, 'handle_bulk_action_ajax' ) ); --- // assets/js/installer.js lines 15-19 $.ajax({ type: "POST", url: sdevs_installer_helper_obj.ajax_url, data: { install_plugin: "woocommerce", action: "install_woocommerce_plugin", }, --- // assets/js/installer.js lines 35-39 $.ajax({ type: "POST", url: sdevs_installer_helper_obj.ajax_url, data: { activate_plugin: "woocommerce", action: "wps_subscription_activate_woocommerce_plugin", },
Security Fix
@@ -131,7 +131,7 @@ url: wp_subscription_ajax.ajaxurl, type: "POST", data: { - action: "wp_subscription_bulk_action", + action: "subscrpt_bulk_action", bulk_action: action, subscription_ids: subscriptionIds, nonce: wp_subscription_ajax.nonce, @@ -15,7 +15,7 @@ url: sdevs_installer_helper_obj.ajax_url, data: { install_plugin: "woocommerce", - action: "install_woocommerce_plugin", + action: "subscrpt_install_woocommerce_plugin", }, beforeSend: function () { $(".sdevs-loading-icon").show(); @@ -35,7 +35,7 @@ url: sdevs_installer_helper_obj.ajax_url, data: { activate_plugin: "woocommerce", - action: "wps_subscription_activate_woocommerce_plugin", + action: "subscrpt_activate_woocommerce_plugin", }, beforeSend: function () { $(".sdevs-loading-icon").show(); @@ -15,7 +15,7 @@ public function __construct() { add_action( 'admin_menu', array( $this, 'create_admin_menu' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) ); - add_action( 'wp_ajax_wp_subscription_bulk_action', array( $this, 'handle_bulk_action_ajax' ) ); + add_action( 'wp_ajax_subscrpt_bulk_action', array( $this, 'handle_bulk_action_ajax' ) ); } /** @@ -43,7 +43,7 @@ 'sdevs_subscription_admin', 'wp_subscription_ajax', array( - 'nonce' => wp_create_nonce( 'wp_subscription_bulk_action_nonce' ), + 'nonce' => wp_create_nonce( 'subscrpt_bulk_action_nonce' ), 'ajaxurl' => admin_url( 'admin-ajax.php' ), ) );
Exploit Outline
1. Identify the target site's AJAX endpoint at `/wp-admin/admin-ajax.php`. 2. Construct a malicious HTML page containing a hidden form or a JavaScript snippet that automatically sends a POST request to this endpoint. 3. For bulk actions, the payload should include `action=wp_subscription_bulk_action`, `bulk_action=delete`, and a list of subscription IDs in the `subscription_ids[]` parameter. 4. For installer actions, the payload should include `action=install_woocommerce_plugin` or `action=wps_subscription_activate_woocommerce_plugin`. 5. Trick an authenticated administrator into clicking a link to the malicious page while they have an active session on the WordPress dashboard. 6. The browser will automatically submit the request with the administrator's cookies, and because the server-side AJAX handler fails to properly validate a unique nonce, the action (e.g., deleting all subscriptions) will be executed.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.