CVE-2026-1710

WooPayments <= 10.5.1 - Missing Authorization to Unauthenticated Plugin Settings Update via save_upe_appearance_ajax

mediumImproper Authorization
6.5
CVSS Score
6.5
CVSS Score
medium
Severity
10.6.0
Patched in
7d
Time to patch

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:L
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
Low
Availability

Technical Details

Affected versions<=10.5.1
PublishedMarch 30, 2026
Last updatedApril 6, 2026
Affected pluginwoocommerce-payments

What Changed in the Fix

Changes introduced in v10.6.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# 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

  1. Entry Point: An unauthenticated POST request is sent to admin-ajax.php with action=save_upe_appearance.
  2. 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' ] );
    
  3. Vulnerable Function: The save_upe_appearance_ajax function is invoked.
  4. Missing Check: The function likely verifies a nonce (if provided) but omits:
    if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die(); }
    
  5. Sink: The function processes the $_POST['appearance'] data and updates a WordPress option, likely _wcpay_upe_appearance or similar, using update_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.

  1. Identify Localization: Search the codebase for wp_create_nonce( 'wcpay_save_upe_appearance' ) or similar. Based on dist/blocks-checkout.js, look for variables related to wcpayConfig.
  2. Trigger Script Loading: The UPE scripts are loaded on the WooCommerce Checkout page.
  3. Manual Extraction Plan:
    • Create a product and add it to the cart.
    • Navigate to the Checkout page (/checkout/).
    • Use browser_eval to find the nonce.
    • JS Variable Guess (to be verified): window.wcpayConfig?.appearance_nonce or window.wcPaySettings?.nonce.
    • Exact check: Inspect the HTML source for wcpay_payment_fields_js_config (mentioned in changelog.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

  1. Install WooCommerce & WooPayments.
  2. 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"
    
  3. Enable WooPayments (requires some mocking of the connection state, usually bypassable in test environments via add_filter( 'wcpay_is_connected', '__return_true' )).
  4. Add Product to Cart:
    Navigate to /checkout/?add-to-cart=[PRODUCT_ID].

7. Expected Results

  • Response: The server should return a 200 OK or 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 nonce parameter first. Some WooPayments AJAX handlers incorrectly use check_ajax_referer with the die parameter set to false, continuing execution regardless.
  • Different Nonce Actions: If wcpay_save_upe_appearance is not the action, search for wp_create_nonce calls in includes/class-ajax-handler.php (inferred path) to find the correct string.
  • Direct Option Guess: If _wcpay_upe_appearance is not the option name, run wp option list --search="*wcpay*appearance*" to find the exact key.
Research Findings
Static analysis — not yet PoC-verified

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

--- a/includes/class-ajax-handler.php
+++ b/includes/class-ajax-handler.php
@@ -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.