UpsellWP <= 2.2.3 - Missing Authorization
Description
The UpsellWP plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.2.3. 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
<=2.2.3Since the source code for version 2.2.3 is not provided, this research plan is based on the vulnerability description, the plugin's known architecture (slug: `checkout-upsell-and-order-bumps`), and common "Missing Authorization" patterns in WooCommerce-related plugins. ### 1. Vulnerability Summary …
Show full research plan
Since the source code for version 2.2.3 is not provided, this research plan is based on the vulnerability description, the plugin's known architecture (slug: checkout-upsell-and-order-bumps), and common "Missing Authorization" patterns in WooCommerce-related plugins.
1. Vulnerability Summary
The UpsellWP plugin (<= 2.2.3) fails to implement proper capability checks on one or more of its AJAX or admin-side handlers. While these handlers are intended for administrative use (managing upsells and order bumps), they are registered in a way that allows any authenticated user—including those with Subscriber roles—to trigger them. This allows an attacker to modify plugin settings, create malicious offers, or disrupt the store's checkout flow.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action: Likely
upsell_wp_save_settings,upsell_wp_update_offer, orupsell_wp_toggle_offer_status(inferred). - Authentication: Authenticated (Subscriber or higher).
- Payload Parameter:
action,nonce(if checked), and data parameters (e.g.,settings_dataoroffer_id). - Preconditions: The attacker must have a valid Subscriber-level session cookie.
3. Code Flow (Inferred)
- Entry Point: The plugin registers an AJAX action in its main class or an admin-specific class:
add_action( 'wp_ajax_upsell_wp_save_settings', [ $this, 'save_settings_callback' ] ); - Missing Check: Inside
save_settings_callback, the code likely performs a nonce check but fails to callcurrent_user_can( 'manage_options' ). - Sink: The function proceeds to update the database using
update_option()or$wpdb->update()based on values provided in$_POST.
4. Nonce Acquisition Strategy
Many WooCommerce plugins localize nonces for the admin dashboard. Since Subscribers can access wp-admin/profile.php, we must check if the plugin enqueues its scripts globally in the admin area.
- Identify Nonce Action: Grep for
wp_create_noncein the plugin folder to find the action string (e.g.,upsell-wp-nonce). - Identify JS Variable: Grep for
wp_localize_scriptto find the object name (e.g.,upsell_wp_vars). - Extraction:
- Create a Subscriber user and log in.
- Navigate to
wp-admin/profile.php. - Use
browser_evalto extract the nonce:browser_eval("window.upsell_wp_vars?.nonce")(inferred name).
- Bypass Check: If
check_ajax_refereruses a generic action like-1or is missing entirely, the nonce may be unnecessary or easily obtained.
5. Exploitation Strategy
We will attempt to disable an existing order bump or change a global setting to demonstrate unauthorized modification.
Step 1: Identify Target Setting
Use WP-CLI to find current settings:wp option get upsell_wp_settings (inferred name).
Step 2: Prepare Payload
We will target an action like saving settings.
- Request Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Content-Type:
application/x-www-form-urlencoded - Parameters:
action:upsell_wp_save_settings(inferred)upsell_wp_nonce:[EXTRACTED_NONCE]settings:{"enable_upsells":"0"}(example payload to disable the plugin's main feature)
Step 3: Execute via http_request
Using the Subscriber's cookies.
6. Test Data Setup
- Plugin Setup: Install UpsellWP 2.2.3 and WooCommerce.
- Configuration: Create at least one "Order Bump" or "Checkout Upsell" via the admin UI.
- Attacker User:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123 - Confirm Target State:
wp option get upsell_wp_settings
7. Expected Results
- HTTP Response: The server should return a
200 OKwith a success indicator (e.g.,{"success":true}or1). - Impact: The targeted setting (e.g.,
enable_upsells) should be modified in the database despite the request coming from a Subscriber.
8. Verification Steps
After sending the HTTP request, verify the change using WP-CLI:
# Verify the option value has changed
wp option get upsell_wp_settings
# Or verify via database directly if options are serialized
wp db query "SELECT option_value FROM wp_options WHERE option_name = 'upsell_wp_settings'"
9. Alternative Approaches
If upsell_wp_save_settings is not the vulnerable action, the researcher should use the following commands to find other candidates:
- List all AJAX actions registered by the plugin:
grep -r "wp_ajax_" wp-content/plugins/checkout-upsell-and-order-bumps/ - Analyze the callbacks for those actions:
Search for callbacks that DO NOT contain the stringcurrent_user_can.# Example: Check if the 'save_offer' function has auth checks grep -A 15 "function save_offer" wp-content/plugins/checkout-upsell-and-order-bumps/path/to/file.php - Check
admin_inithooks:
Some plugins handle form submissions viaadmin_init. Sinceadmin_initruns for all authenticated users (including subscribers) when they accessadmin-ajax.phporadmin-post.php, handlers registered here without capability checks are highly vulnerable.grep -r "add_action.*admin_init" wp-content/plugins/checkout-upsell-and-order-bumps/
Summary
The UpsellWP plugin for WordPress fails to perform capability checks on its AJAX handlers in versions up to 2.2.3. This allows authenticated users with Subscriber-level permissions to modify plugin settings or manipulate WooCommerce upsell offers by sending crafted requests to the WordPress AJAX endpoint.
Vulnerable Code
// Inferred code structure based on common patterns in the affected plugin version // Path: wp-content/plugins/checkout-upsell-and-order-bumps/includes/admin/class-upsell-wp-admin.php public function save_settings_callback() { // Nonce check might exist, but capability check is missing check_ajax_referer('upsell-wp-nonce', 'nonce'); // Vulnerability: No call to current_user_can('manage_options') before processing data $settings = isset($_POST['settings']) ? $_POST['settings'] : array(); update_option('upsell_wp_settings', $settings); wp_send_json_success(); }
Security Fix
@@ -10,6 +10,10 @@ public function save_settings_callback() { check_ajax_referer('upsell-wp-nonce', 'nonce'); + if (!current_user_can('manage_options')) { + wp_send_json_error('Unauthorized', 403); + } + $settings = isset($_POST['settings']) ? $_POST['settings'] : array(); update_option('upsell_wp_settings', $settings); wp_send_json_success();
Exploit Outline
1. Login to the WordPress site as a user with Subscriber-level permissions. 2. Access the WordPress admin dashboard (e.g., /wp-admin/profile.php) and inspect the page source or use browser console to extract the AJAX nonce, typically localized by the plugin (e.g., window.upsell_wp_vars.nonce). 3. Construct a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to the vulnerable handler (e.g., 'upsell_wp_save_settings'). 4. Include the extracted 'nonce' and a 'settings' payload designed to disable features or modify offer parameters. 5. Send the request and verify the modification by checking the plugin's configuration via the UI or database (e.g., 'wp option get upsell_wp_settings').
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.