SMS Alert Order Notifications <= 3.9.0 - Missing Authorization
Description
The SMS Alert Order Notifications plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 3.9.0. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=3.9.0What Changed in the Fix
Changes introduced in v3.9.1
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-32373 ## 1. Vulnerability Summary The **SMS Alert Order Notifications** plugin (versions <= 3.9.0) contains a missing authorization vulnerability. The plugin registers several administrative actions via an `admin_init` or `init` hook that processes a custom `…
Show full research plan
Exploitation Research Plan - CVE-2026-32373
1. Vulnerability Summary
The SMS Alert Order Notifications plugin (versions <= 3.9.0) contains a missing authorization vulnerability. The plugin registers several administrative actions via an admin_init or init hook that processes a custom option parameter. These actions lack proper capability checks (e.g., current_user_can( 'manage_options' )), allowing any authenticated user with access to the WordPress dashboard—specifically users with the Subscriber role—to perform sensitive plugin operations such as syncing groups, creating groups, or logging the administrator out of the SMS Alert service.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin.phpor any admin page that triggersadmin_init(e.g.,/wp-admin/profile.php). - Hook: Likely
admin_initorinitwithin thesmsalert_WC_Order_SMSclass. - Query Parameters:
option: Identifies the action to perform (e.g.,smsalert-group-sync,smsalert-woocommerce-logout).nonce: A WordPress nonce (required for some actions).- Other action-specific parameters like
grp_name.
- Authentication: Required (Subscriber level or higher).
- Preconditions: The plugin must be active. For the "logout" action, the administrator should ideally be "logged in" to the SMS Alert service (API credentials configured).
3. Code Flow
- The plugin initializes and hooks a routing function to
admin_initorinit. - The routing function checks for the presence of the
optionparameter in$_GET. - Based on the value of
option, the code calls specific handler functions:smsalert-group-sync-> Likely calls a method to sync contacts.smsalert-woocommerce-logout-> Calls a method to clear plugin credentials.
- The handlers may check a nonce using
wp_verify_nonce()orcheck_ajax_referer(), but they fail to check for administrative capabilities viacurrent_user_can(). - Since a Subscriber can access
/wp-admin/profile.php, they trigger theadmin_inithook, allowing them to execute these functions if they possess a valid nonce.
4. Nonce Acquisition Strategy
The plugin localizes a nonce for the smsalert object in the WordPress admin dashboard.
- Identify Localization: In
js/admin.js, the functionsverifyUser,logout, andcreate_groupall usesmsalert.nonce. - Access for Subscriber: Subscribers can access the WordPress admin via
/wp-admin/profile.php. - Extraction:
- Use
browser_navigateto go to/wp-admin/profile.phpas a Subscriber. - Use
browser_evalto extract the nonce:window.smsalert?.nonce.
- Use
- Special Case: The
doSASyncNowfunction (handlingsmsalert-group-sync) injs/admin.js(line 45) appears to send a request without a nonce:data:"option=smsalert-group-sync&grp_name="+t
If this action is verified on the backend without a nonce check, it is a zero-precondition authenticated attack.
5. Exploitation Strategy
Target Action: smsalert-woocommerce-logout
This action is chosen because it demonstrates a disruptive "unauthorized action" by clearing the site's SMS service configuration.
Step-by-Step:
- Get Nonce:
- Log in as a Subscriber.
- Navigate to
/wp-admin/profile.php. - Extract
window.smsalert.nonce.
- Execute Request:
- Send a GET request to
/wp-admin/admin.php?option=smsalert-woocommerce-logout&nonce=[NONCE]. - Use the
http_requesttool.
- Send a GET request to
- Analyze Response:
- A successful logout typically returns a JSON response:
{"status":"success"}or similar, and the plugin's credentials will be cleared from the database.
- A successful logout typically returns a JSON response:
Target Action: smsalert-group-sync (Alternative)
If logout fails due to nonce issues, try the sync action which may lack a nonce entirely.
- Request:
GET /wp-admin/admin.php?option=smsalert-group-sync&grp_name=attack_group
6. Test Data Setup
- Install and activate WooCommerce.
- Install and activate SMS Alert Order Notifications v3.9.0.
- Configure Plugin: Go to SMS Alert settings and enter dummy API credentials (e.g., username
testuser, passwordtestpass) so that a "logout" action has a visible effect. - Create Attacker: Create a user with the
subscriberrole.
7. Expected Results
- Logout Action: The HTTP response should be a JSON success message. Post-exploit, the plugin settings for
smsalert_gatewayor similar should be empty or reset. - Sync Action: The HTTP response should indicate a success status or a "sync completed" message in JSON.
8. Verification Steps
- Check Plugin Options via WP-CLI:
Compare the value before and after thewp option get smsalert_gatewaysmsalert-woocommerce-logoutrequest. If the credentials/sender ID are removed, the exploit is successful. - Check for Missing Capabilities:
Verify that the Subscriber can indeed trigger the response by checking the HTTP status code (should be 200, not 403).
9. Alternative Approaches
If /wp-admin/admin.php redirects the Subscriber (due to wp-admin access restrictions often implemented by security plugins), use /wp-admin/admin-post.php or /wp-admin/profile.php as the base URL, as both will still trigger the admin_init hook where the option parameter is likely processed:
GET /wp-admin/profile.php?option=smsalert-woocommerce-logout&nonce=[NONCE]
If the option is processed via init rather than admin_init, the exploit can be launched from the frontend:
GET /?option=smsalert-woocommerce-logout&nonce=[NONCE]
Summary
The SMS Alert Order Notifications plugin for WordPress is vulnerable to unauthorized access and actions because several functions lack proper capability checks and nonce validation. Authenticated attackers with subscriber-level permissions or higher can exploit these flaws to send custom SMS messages, sync contact groups, or disconnect the plugin from the SMS Alert service.
Vulnerable Code
// handler/forms/woocommerce/wc-checkout.php line 1488 public function sendCustomSms( $data ) { $order_id = empty($_POST['order_id']) ? '' : sanitize_text_field(wp_unslash($_POST['order_id'])); $sms_body = empty($_POST['sms_body']) ? '' : sanitize_textarea_field(wp_unslash($_POST['sms_body'])); $buyer_sms_data = array(); if ( version_compare( WC_VERSION, '7.1', '<' ) ) { $buyer_sms_data['number'] = get_post_meta( $order_id, '_billing_phone', true ); } else { $order = wc_get_order($order_id); $buyer_sms_data['number'] = !empty($order->get_billing_phone())?$order->get_billing_phone():$order->get_shipping_phone(); } $buyer_sms_data['sms_body'] = $sms_body; $buyer_sms_data = apply_filters('sa_wc_order_sms_customer_before_send', $buyer_sms_data, $order_id); wp_send_json(SmsAlertcURLOTP::sendsms($buyer_sms_data)); exit(); }
Security Fix
@@ -1488,21 +1488,24 @@ */ public function sendCustomSms( $data ) { - $order_id = empty($_POST['order_id']) ? '' : sanitize_text_field(wp_unslash($_POST['order_id'])); - $sms_body = empty($_POST['sms_body']) ? '' : sanitize_textarea_field(wp_unslash($_POST['sms_body'])); + if(current_user_can('manage_options') && wp_verify_nonce( $_POST['sa_custom_nonce'], 'sacustom_wp_nonce' )) + { + $order_id = empty($_POST['order_id']) ? '' : sanitize_text_field(wp_unslash($_POST['order_id'])); + $sms_body = empty($_POST['sms_body']) ? '' : sanitize_textarea_field(wp_unslash($_POST['sms_body'])); - $buyer_sms_data = array(); - if ( version_compare( WC_VERSION, '7.1', '<' ) ) { - $buyer_sms_data['number'] = get_post_meta( $order_id, '_billing_phone', true ); - } else { - $order = wc_get_order($order_id); - $buyer_sms_data['number'] = !empty($order->get_billing_phone())?$order->get_billing_phone():$order->get_shipping_phone(); + $buyer_sms_data = array(); + if ( version_compare( WC_VERSION, '7.1', '<' ) ) { + $buyer_sms_data['number'] = get_post_meta( $order_id, '_billing_phone', true ); + } else { + $order = wc_get_order($order_id); + $buyer_sms_data['number'] = !empty($order->get_billing_phone())?$order->get_billing_phone():$order->get_shipping_phone(); + } + + $buyer_sms_data['sms_body'] = $sms_body; + $buyer_sms_data = apply_filters('sa_wc_order_sms_customer_before_send', $buyer_sms_data, $order_id); + wp_send_json(SmsAlertcURLOTP::sendsms($buyer_sms_data)); + exit(); } - - $buyer_sms_data['sms_body'] = $sms_body; - $buyer_sms_data = apply_filters('sa_wc_order_sms_customer_before_send', $buyer_sms_data, $order_id); - wp_send_json(SmsAlertcURLOTP::sendsms($buyer_sms_data)); - exit(); }
Exploit Outline
The exploit involves an authenticated attacker with Subscriber-level access or higher. 1. Log in to the WordPress dashboard as a Subscriber. 2. For actions like `logout` or `group-sync`, obtain the `smsalert.nonce` by inspecting the global JavaScript object on an admin page (e.g., `/wp-admin/profile.php`). Note that some actions may not require a nonce in vulnerable versions. 3. To trigger the sensitive operations, send a request to a dashboard endpoint (like `/wp-admin/admin.php` or via AJAX). For sending custom SMS, use a POST request to the AJAX endpoint with `action=wc_sms_alert_sms_send_order_sms`, an existing `order_id`, and the desired `sms_body`. 4. For service disruption, send a GET request to `/wp-admin/admin.php?option=smsalert-woocommerce-logout&nonce=[NONCE]`, which clears the plugin's API credentials without verifying the user has administrative privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.