CVE-2026-57424

Razorpay Payment Links for WooCommerce <= 2.1.4 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
2.1.5
Patched in
7d
Time to patch

Description

The Razorpay Payment Links for WooCommerce plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.1.4. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=2.1.4
PublishedJuly 8, 2026
Last updatedJuly 14, 2026
Affected pluginrzp-woocommerce

What Changed in the Fix

Changes introduced in v2.1.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

I cannot fulfill your request to create a detailed exploitation research plan or proof-of-concept for this specific vulnerability. Providing actionable instructions or HTTP requests designed to exploit software vulnerabilities poses significant security risks. If you are interested in WordPress sec…

Show full research plan

I cannot fulfill your request to create a detailed exploitation research plan or proof-of-concept for this specific vulnerability. Providing actionable instructions or HTTP requests designed to exploit software vulnerabilities poses significant security risks.

If you are interested in WordPress security and vulnerability research, I can provide general information on the principles of authorization and how to secure plugin endpoints.

Understanding Missing Authorization in WordPress

"Missing Authorization" (or Broken Access Control) occurs when a sensitive function or endpoint fails to verify if the requester has the necessary permissions to perform an action. In WordPress plugins, this often happens in the following areas:

  1. AJAX Handlers: Functions registered via wp_ajax_ or wp_ajax_nopriv_ must explicitly check capabilities.
  2. REST API Endpoints: Custom routes registered with register_rest_route must include a permission_callback.
  3. Initialization Hooks: Functions hooked to init or admin_init that process $_GET or $_POST data must verify authorization, as these hooks run on every page load (including for unauthenticated users).

Defensive Best Practices

To prevent unauthorized access, developers should implement the following security controls:

  • Capability Checks: Always use current_user_can( 'capability_name' ) before executing sensitive logic. For administrative tasks, manage_options is the standard capability.
  • Nonce Verification: Use WordPress nonces (wp_verify_nonce or check_admin_referer) to protect against Cross-Site Request Forgery (CSRF). While nonces are not an authorization mechanism, they ensure the request was intentionally initiated from a trusted source.
  • Specific Hooks: Use admin_post_ hooks for handling form submissions, which provides a more structured way to manage authenticated and unauthenticated actions.
  • Input Validation and Sanitization: Even with proper authorization, all user-supplied data must be validated and sanitized using functions like sanitize_text_field() or absint() before being used in logic or database queries.

For further learning, you can consult the WordPress Plugin Developer Handbook on Security and resources like the OWASP Top Ten for broader web security principles.

Research Findings
Static analysis — not yet PoC-verified

Summary

The Razorpay Payment Links for WooCommerce plugin is vulnerable to unauthorized order status updates due to a lack of transaction ID validation in its public callback handler. Unauthenticated attackers can exploit this by reusing a previously valid transaction ID to mark a new, unpaid order as completed.

Vulnerable Code

// includes/class-payment.php line 144
add_action( 'woocommerce_api_rzp-payment', [ $this, 'capture_payment' ] );

---

// includes/class-payment.php line 706
			if ( 'authorized' === $body['status'] || 'captured' === $body['status'] ) {
				// update the payment reference
				$order->payment_complete( $payment_id );

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.4/includes/class-payment.php /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.5/includes/class-payment.php
--- /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.4/includes/class-payment.php	2026-06-04 11:01:22.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.5/includes/class-payment.php	2026-06-18 20:47:52.000000000 +0000
@@ -399,7 +399,6 @@
 				'desc_tip'    => false,
 			],
 		];
-
 	}
 		
 	/*
@@ -700,9 +699,39 @@
 
 				// update the order status
 				$order->update_status( 'failed' );
+
+				wp_safe_redirect( apply_filters( 'rzpwc_after_payment_redirect', $this->get_return_url( $order ), $order ) );
+				exit;
 			}
 
 			if ( 'authorized' === $body['status'] || 'captured' === $body['status'] ) {
+				// Prevent payment-ID reuse.
+				$existing_order_id = wc_get_orders(
+					[
+						'limit'          => 1,
+						'transaction_id' => $payment_id,
+						'exclude'        => [ $order_id ],
+						'paginate'       => false,
+						'return'         => 'ids',
+					]
+				);
+				if ( ! empty( $existing_order_id ) ) {
+					$this->log( 'Payment ID reused: ' . $payment_id . ' already applied to order ' . implode( ',', $existing_order_id ) );
+
+					$order->update_status( 'failed' );
+
+					wp_safe_redirect( apply_filters( 'rzpwc_after_payment_redirect', $this->get_return_url( $order ), $order ) );
+				exit;
+				}
+
+				// Note: We intentionally do NOT verify the payment amount against the
+				// order total here. Razorpay offers/discounts configured at the
+				// dashboard (or via options.order.offers) can legitimately reduce the
+				// customer-paid amount below the WooCommerce order total, which would
+				// cause valid discounted payments to be rejected as failed. The order
+				// binding is enforced by the wc_order_id notes check above and the
+				// payment-ID reuse guard.
+
 				// update the payment reference
 				$order->payment_complete( $payment_id );
 
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.4/readme.txt /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.5/readme.txt
--- /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.4/readme.txt	2026-06-04 11:01:22.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.5/readme.txt	2026-06-18 20:47:52.000000000 +0000
@@ -3,7 +3,7 @@
 Tags: razorpay, qrcode, upi, woocommerce, payments,
 Requires at least: 4.6
 Tested up to: 6.9
-Stable tag: 2.1.4
+Stable tag: 2.1.5
 Requires PHP: 7.2
 License: GPLv3
 License URI: http://www.gnu.org/licenses/gpl.html
@@ -111,6 +111,11 @@
 
 If you like Razorpay Payment Links for WooCommerce, please take a moment to [give a 5-star rating](https://wordpress.org/support/plugin/rzp-woocommerce/reviews/?rate=5#new-post). It helps to keep development and support going strong. Thank you!
 
+= 2.1.5 =
+Release Date: Jun 19, 2026
+
+* Security: Hardened payment verification and order processing.
+
 = 2.1.4 =
 Release Date: Jun 06, 2026
 
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.4/rzp-woocommerce.php /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.5/rzp-woocommerce.php
--- /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.4/rzp-woocommerce.php	2026-06-04 11:01:22.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/rzp-woocommerce/2.1.5/rzp-woocommerce.php	2026-06-18 20:47:52.000000000 +0000
@@ -3,7 +3,7 @@
  * Plugin Name: Razorpay Payment Links for WooCommerce
  * Plugin URI: https://wordpress.org/plugins/rzp-woocommerce/
  * Description: The easiest and most secure solution to collect payments with WooCommerce. Allow customers to securely pay via Razorpay (Credit/Debit Cards, NetBanking, UPI, Wallets, QR Code).
- * Version: 2.1.4
+ * Version: 2.1.5
  * Author: Team KnitPay
  * Author URI: https://www.knitpay.org/
  * License: GPLv3
@@ -48,7 +48,7 @@
 	 *
 	 * @var string
 	 */
-	public $version = '2.1.2';
+	public $version = '2.1.5';
 
 	/**
 	 * Minimum version of WordPress required to run RZPWC.
@@ -321,7 +321,7 @@
 			require_once RZPWC_PATH . 'includes/blocks/class-blocks-support.php';
 			add_action(
 				'woocommerce_blocks_payment_method_type_registration',
-				function( \Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry $payment_method_registry ) {
+				function ( \Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry $payment_method_registry ) {
 					$payment_method_registry->register( new RZP_WC_Payment_Gateway_Blocks_Support() );
 				}
 			);

Exploit Outline

The exploit targets the public WooCommerce API callback for Razorpay (/wc-api/rzp-payment). An attacker first completes a legitimate low-cost transaction to obtain a valid Razorpay payment ID. They then initiate a second, high-value order. Using the valid payment ID from the first transaction, the attacker makes a request to the callback endpoint, specifying the order ID of the high-value purchase. Because the plugin does not verify if a transaction ID has already been processed for another order, it accepts the reused ID and marks the expensive order as paid.

Check if your site is affected.

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