Razorpay Payment Links for WooCommerce <= 2.1.4 - Missing Authorization
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:NTechnical Details
<=2.1.4What Changed in the Fix
Changes introduced in v2.1.5
Source Code
WordPress.org SVNI 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:
- AJAX Handlers: Functions registered via
wp_ajax_orwp_ajax_nopriv_must explicitly check capabilities. - REST API Endpoints: Custom routes registered with
register_rest_routemust include apermission_callback. - Initialization Hooks: Functions hooked to
initoradmin_initthat process$_GETor$_POSTdata 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_optionsis the standard capability. - Nonce Verification: Use WordPress nonces (
wp_verify_nonceorcheck_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()orabsint()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.
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
@@ -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 ); @@ -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 @@ -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.