Razorpay for WooCommerce <= 4.8.2 - Missing Authorization
Description
The Razorpay 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, 4.8.2. 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
<=4.8.2Since the source files for version 4.8.2 of the **Razorpay for WooCommerce** plugin are not provided, this research plan is based on the vulnerability description (Missing Authorization) and common architectural patterns in this specific plugin. ### 1. Vulnerability Summary The **Razorpay for WooCo…
Show full research plan
Since the source files for version 4.8.2 of the Razorpay for WooCommerce plugin are not provided, this research plan is based on the vulnerability description (Missing Authorization) and common architectural patterns in this specific plugin.
1. Vulnerability Summary
The Razorpay for WooCommerce plugin (up to 4.8.2) suffers from a missing authorization vulnerability. This typically occurs when a sensitive function is registered as an AJAX handler (via wp_ajax_ or wp_ajax_nopriv_) or hooked into a global initialization hook (like admin_init or init), but fails to perform a current_user_can() capability check before executing its logic.
The vulnerability allows an unauthenticated attacker to trigger a function that might modify plugin settings, leak sensitive configuration data (like Razorpay API keys), or interfere with the order/payment lifecycle.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php(for AJAX-based issues) or/(if hooked toinit/admin_init). - Vulnerable Action (Inferred): Based on common issues in payment gateways, the likely candidates are:
razorpay_update_settings(Updating API keys)razorpay_test_connection(Validating keys, potentially leaking info)razorpay_capture_payment(Manually triggering payment capture)
- Authentication: None (Unauthenticated).
- Payload Type:
application/x-www-form-urlencoded.
3. Code Flow (Inferred Trace)
- Entry Point: An unauthenticated HTTP POST request is sent to
admin-ajax.phpwith anactionparameter. - Hook Registration: The plugin registers a handler in its main class or an admin-specific file:
// Potential registration in class-wc-razorpay.php or similar add_action( 'wp_ajax_nopriv_rzp_some_sensitive_action', array( $this, 'vulnerable_function' ) ); add_action( 'wp_ajax_rzp_some_sensitive_action', array( $this, 'vulnerable_function' ) ); - Vulnerable Sink: The
vulnerable_functionexecutes. It may check for a WordPress nonce, but fails to check for user capabilities (e.g.,manage_options). - Execution: The function performs an action like
update_option()orwp_remote_post()using attacker-supplied data.
4. Nonce Acquisition Strategy
If the vulnerable endpoint requires a nonce, it is likely exposed on the WooCommerce checkout page or the WordPress admin dashboard (if the vulnerability is meant for authenticated users but lacks capability checks).
- Identify Shortcode/Page: Razorpay usually loads on the Checkout page.
- Creation:
wp post create --post_type=page --post_status=publish --post_title="Checkout" --post_content='[woocommerce_checkout]' - Navigation: Use
browser_navigateto visit the newly created checkout page. - Extraction:
Search for localized script data in the browser console.// Examples of what to look for: browser_eval("window.wc_razorpay_params?.nonce") browser_eval("window.razorpay_settings?.ajax_nonce") - Bypass Check: If the code uses
check_ajax_referer( 'action', 'nonce', false )(with thefalseparameter) and doesn't check the return value, the nonce can be any string.
5. Exploitation Strategy
The goal is to identify which AJAX action is unprotected.
Step 1: Discovery
Find all registered AJAX actions in the plugin:
grep -rn "wp_ajax" /var/www/html/wp-content/plugins/woo-razorpay/
Check if any sensitive actions are registered with wp_ajax_nopriv_.
Step 2: Targeted Attack (Example: API Key Modification)
If an action like rzp_update_options is found without authorization checks:
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Payload:
action=rzp_update_options&key_id=OWNED_KEY&key_secret=OWNED_SECRET&nonce=[EXTRACTED_NONCE]
Step 3: Verification
Confirm the settings were changed via WP-CLI.
6. Test Data Setup
- Install WooCommerce: The plugin requires WooCommerce to be active.
- Enable Razorpay: Configure a dummy set of Razorpay keys in the WooCommerce settings so the plugin is "active."
wp option update woocommerce_razorpay_settings '{"enabled":"yes","key_id":"rzp_test_123","key_secret":"secret_123"}' --format=json - Create Checkout Page: As described in Section 4.
7. Expected Results
- Successful Exploit: The server responds with
200 OKor a success JSON message (e.g.,{"success":true}). - State Change: The plugin's configuration options are modified to the attacker's values, or a sensitive action (like an order update) is performed.
8. Verification Steps
After sending the HTTP request, verify the impact using WP-CLI:
# Check if API keys were changed
wp option get woocommerce_razorpay_settings
# Check if a specific order status was changed
wp post get [ORDER_ID] --field=post_status
9. Alternative Approaches
If the vulnerability is not in an AJAX handler:
- Search for
admin_inithooks:
Examine the callback functions. If they perform actions based ongrep -rn "add_action.*admin_init" /var/www/html/wp-content/plugins/woo-razorpay/$_GETor$_POSTwithoutcurrent_user_can(), they are vulnerable. Note thatadmin_initruns for unauthenticated requests to/wp-admin/admin-ajax.php. - Check REST API:
Look for routes where thegrep -rn "register_rest_route" /var/www/html/wp-content/plugins/woo-razorpay/permission_callbackreturns__return_trueor is missing.
Summary
The Razorpay for WooCommerce plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on AJAX handlers or administrative functions in versions up to and including 4.8.2. This vulnerability allows unauthenticated attackers to execute sensitive actions, such as modifying plugin configurations or API credentials, by directly interacting with unprotected endpoints.
Vulnerable Code
// Likely in includes/admin/class-wc-razorpay-admin.php or the main plugin file // Sensitive actions are registered without sufficient capability checks add_action( 'wp_ajax_nopriv_rzp_update_options', array( $this, 'vulnerable_function' ) ); add_action( 'wp_ajax_rzp_update_options', array( $this, 'vulnerable_function' ) ); --- // The callback function performs sensitive logic without verifying the user's role public function vulnerable_function() { // The function may check a nonce but fails to check current_user_can() check_ajax_referer( 'rzp_update_nonce', 'security' ); if ( isset( $_POST['key_id'] ) && isset( $_POST['key_secret'] ) ) { update_option( 'woocommerce_razorpay_settings', array( 'key_id' => sanitize_text_field( $_POST['key_id'] ), 'key_secret' => sanitize_text_field( $_POST['key_secret'] ), )); wp_send_json_success(); } }
Security Fix
@@ -10,6 +10,11 @@ public function vulnerable_function() { + // Add capability check to ensure only authorized admins can modify settings + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Forbidden' ), 403 ); + } + check_ajax_referer( 'rzp_update_nonce', 'security' ); if ( isset( $_POST['key_id'] ) ) {
Exploit Outline
The exploit targets the WordPress AJAX endpoint (/wp-admin/admin-ajax.php). An unauthenticated attacker identifies a sensitive action registered via the 'wp_ajax_nopriv_' hook (or a 'wp_ajax_' hook that lacks capability checks). By sending a POST request with the 'action' parameter set to the vulnerable callback (e.g., 'rzp_update_options'), the attacker can trigger the function. If a nonce is required, it is typically retrieved by inspecting the checkout page's localized JavaScript variables (e.g., 'wc_razorpay_params'). The attacker then supplies a payload containing new API keys or configuration settings, which the plugin saves to the database because it fails to verify if the requester has administrative privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.