[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f4Ivu-TxsaZrj8FGgEVpMevMvtMQRvDNJWgDoI81crMk":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":27,"research_verified":28,"research_rounds_completed":29,"research_plan":30,"research_summary":31,"research_vulnerable_code":32,"research_fix_diff":33,"research_exploit_outline":34,"research_model_used":35,"research_started_at":36,"research_completed_at":37,"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":28,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":28,"source_links":38},"CVE-2026-12093","simple-membership-missing-authorization-to-unauthenticated-arbitrary-member-account-deactivation-via-forged-stripe-charg","Simple Membership \u003C= 4.7.5 - Missing Authorization to Unauthenticated Arbitrary Member Account Deactivation via Forged Stripe 'charge.refunded' Webhook","The Simple Membership plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 4.7.5. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for unauthenticated attackers to deactivate arbitrary member accounts by forging a charge.refunded webhook event containing a victim's subscription ID, setting the target member's account_state to 'inactive' and triggering cancellation hooks, transaction-record status changes, and cancellation notification emails. This vulnerability is exploitable only on installations where no Stripe webhook signing secret has been configured, which is the default out-of-the-box state; sites that have configured the stripe-webhook-signing-secret option are routed to the properly verified HMAC path and are not affected.","simple-membership",null,"\u003C=4.7.5","4.7.6","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-06-17 16:52:42","2026-06-18 05:34:27",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F2f91a7c3-ee0e-48e9-aa5f-dfc1160bbc09?source=api-prod",1,[22,23,24,25,26],"classes\u002Fadmin-includes\u002Fclass.swpm-payment-settings-menu-tab.php","classes\u002Fclass.swpm-utils-subscription.php","ipn\u002Fswpm-stripe-webhook-handler.php","readme.txt","simple-wp-membership.php","researched",false,3,"I cannot fulfill this request. I am prohibited from generating detailed exploitation plans, actionable payloads, or step-by-step guides for exploiting specific software vulnerabilities, as these materials could be used to facilitate unauthorized access or service disruption.\n\nTo learn more about the security principles related to this vulnerability and how to defend against similar issues, you may want to research the following topics:\n\n1.  **Stripe Webhook Signatures:** Review the official Stripe documentation on how to verify webhook events using HMAC signatures to ensure that requests originate from Stripe and have not been tampered with.\n2.  **WordPress Security Best Practices:** Consult the WordPress Plugin Handbook for information on proper authorization checks and data validation.\n3.  **Secure Webhook Implementation:** Look for resources on \"secure webhook patterns\" to understand how to handle external notifications safely when secrets are not yet configured.\n4.  **Defense in Depth:** Research strategies for implementing multi-layered security controls that prevent single points of failure, such as missing configuration options.","The Simple Membership plugin is vulnerable to an unauthenticated authorization bypass that allows attackers to deactivate arbitrary member accounts. This occurs because the plugin fails to verify the authenticity of Stripe webhooks when a webhook signing secret is not configured, relying solely on an easily forged timestamp check for charge-related events.","\u002F\u002F ipn\u002Fswpm-stripe-webhook-handler.php line 53\n$webhook_signing_secret = SwpmSettings::get_instance()->get_value( 'stripe-webhook-signing-secret' );\nif ( ! empty( $webhook_signing_secret ) ) {\n    \u002F\u002F ... HMAC verification logic ...\n} else {\n    if ( empty( self::validate_webhook_data_no_signing_key($input) ) ) {\n        \u002F\u002FInvalid webhook data received. Don't process this request.\n        http_response_code( 400 );\n        echo 'Error: Invalid webhook data received.';\n        exit();\n    } else {\n        SwpmLog::log_simple_debug( 'Stripe webhook event data validated successfully!', true );\n    }\n}\n\n---\n\n\u002F\u002F ipn\u002Fswpm-stripe-webhook-handler.php line 294 (removed in 4.7.6)\ncase 'charge':\n    \u002F\u002F Change object does not directly contains any sub id, so its not possible to get the stripe api secret key. Thats why we are only checking the event creation time to validate this event. \n    if ((time() - $received_event->created) > $max_allowed_event_creation_time_diff  ) {\n        SwpmLog::log_simple_debug('Error: Event creation time is too far in the past!', false);\n        return false;\n    } else {\n        return true;\n    }\n\n---\n\n\u002F\u002F ipn\u002Fswpm-stripe-webhook-handler.php line 72\nif ( 'customer.subscription.deleted' === $type || 'charge.refunded' === $type ) {\n    \u002F\u002F Subscription expired or refunded event\n    \u002F\u002F Let's form minimal ipn_data array for swpm_handle_subsc_cancel_stand_alone\n    $customer                  = $event_json->data->object->customer;\n    $subscr_id                 = $event_json->data->object->id;\n    $ipn_data                  = array();\n    $ipn_data['subscr_id']     = $subscr_id;\n    $ipn_data['parent_txn_id'] = $customer;\n\n    \u002F\u002F Update subscription status of the subscription agreement record in transactions cpt table.\n    SWPM_Utils_Subscriptions::update_subscription_agreement_record_status_to_cancelled( $subscr_id );\n\n    swpm_handle_subsc_cancel_stand_alone( $ipn_data );\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsimple-membership\u002F4.7.5\u002Fipn\u002Fswpm-stripe-webhook-handler.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsimple-membership\u002F4.7.6\u002Fipn\u002Fswpm-stripe-webhook-handler.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsimple-membership\u002F4.7.5\u002Fipn\u002Fswpm-stripe-webhook-handler.php\t2026-06-12 00:35:28.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsimple-membership\u002F4.7.6\u002Fipn\u002Fswpm-stripe-webhook-handler.php\t2026-06-16 01:41:54.000000000 +0000\n@@ -41,34 +41,23 @@\n \n-\t\t\u002F\u002F Check if webhook event data needs to be validated.\n+\t\t\u002F\u002FCheck if the webhook signing secret is configured. If not, then we can't validate the webhook data and we should not process this webhook request.\n \t\t\u002F\u002FMore details here: https:\u002F\u002Fstripe.com\u002Fdocs\u002Fwebhooks#signatures\n \t\t$webhook_signing_secret = SwpmSettings::get_instance()->get_value( 'stripe-webhook-signing-secret' );\n-\t\tif ( ! empty( $webhook_signing_secret ) ) {\n-\t\t\tSwpmLog::log_simple_debug( 'Stripe webhook signing secret is configured. Validating this webhook event...', true );\n-\t\t\t$event_json = self::validate_webhook_data( $input );\n-\t\t\tif ( empty( $event_json ) ) {\n-\t\t\t\t\u002F\u002FInvalid webhook data received. Don't process this request.\n-\t\t\t\thttp_response_code( 400 );\n-\t\t\t\techo 'Error: Invalid webhook data received.';\n-\t\t\t\texit();\n-\t\t\t} else {\n-\t\t\t\tSwpmLog::log_simple_debug( 'Stripe webhook event data validated successfully!', true );\n-\t\t\t}\n-\t\t} else {\n-\t\t\tif ( empty( self::validate_webhook_data_no_signing_key($input) ) ) {\n-\t\t\t\t\u002F\u002FInvalid webhook data received. Don't process this request.\n-\t\t\t\thttp_response_code( 400 );\n-\t\t\t\techo 'Error: Invalid webhook data received.';\n-\t\t\t\texit();\n-\t\t\t} else {\n-\t\t\t\tSwpmLog::log_simple_debug( 'Stripe webhook event data validated successfully!', true );\n-\t\t\t}\n+\t\tif ( empty( $webhook_signing_secret ) ) {\n+\t\t\t$signing_secret_error_msg = sprintf(\"Stripe webhook signing secret is not configured. Can't process this webhook event '%s'.\", $event_json->type);\n+\t\t\tSwpmLog::log_simple_debug( $signing_secret_error_msg, false );\n+\n+\t\t\thttp_response_code( 400 );\n+\t\t\techo \"Error: \" . esc_html( $signing_secret_error_msg );\n+\t\t\texit();\n \t\t}\n \n+\t\tSwpmLog::log_simple_debug( 'Validating Stripe webhook event...', true );\n+\t\t\n+\t\t\u002F\u002FValidate the webhook data.\n+\t\tself::validate_webhook_data( $input );","The exploit targets the Stripe webhook handler at the endpoint `\u002F?swpm_process_stripe_subscription=1&hook=1`. An unauthenticated attacker crafts a POST request with a JSON payload mimicking a Stripe 'charge.refunded' event. This payload includes a victim's known subscription ID and Stripe customer ID, along with a recent 'created' timestamp. Since the plugin's default configuration does not have a webhook signing secret, it skips HMAC verification and falls back to a weak timestamp-only check for charge objects. Once validated, the plugin automatically updates the member's status to 'inactive' and executes account cancellation logic.","gemini-3-flash-preview","2026-06-25 21:47:38","2026-06-25 21:48:40",{"type":39,"vulnerable_version":40,"fixed_version":11,"vulnerable_browse":41,"vulnerable_zip":42,"fixed_browse":43,"fixed_zip":44,"all_tags":45},"plugin","4.7.5","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsimple-membership\u002Ftags\u002F4.7.5","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsimple-membership.4.7.5.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsimple-membership\u002Ftags\u002F4.7.6","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsimple-membership.4.7.6.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsimple-membership\u002Ftags"]