SePay Gateway <= 1.1.20 - Unauthenticated Information Exposure
Description
The SePay Gateway plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 1.1.20. This makes it possible for unauthenticated attackers to extract sensitive user or configuration data.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:NTechnical Details
What Changed in the Fix
Changes introduced in v1.1.21
Source Code
WordPress.org SVN_pay_code_prefixes`, `sepay_get_bank_sub_accounts`. * Vulnerability: Missing capability check AND registered as `nopriv`. Let's check the CVSS: 5.3. This is exactly what a "Confidentiality: Low" bug looks like. IDOR to see order status or exposure of bank details fits perfectly. *Not…
Show full research plan
_pay_code_prefixes, sepay_get_bank_sub_accounts. * Vulnerability: Missing capability check AND registered as nopriv`.
Let's check the CVSS: 5.3. This is exactly what a "Confidentiality: Low" bug looks like. IDOR to see order status or exposure of bank details fits perfectly.
*Note on Nonce Acquisition:*
I need to find where `sepay_vars` is.
I'll check the Checkout page.
I'll also check if `submit_order` is a standard nonce or if the plugin created it.
1. Install SePay Gateway <= 1.1.20.
2. Enable the gateway.
3. Create a "Customer" user and a downloadable product.
4. As the customer, place an order. Note the Order ID (e.g., 100).
5. As an **unauthenticated** visitor, go to the Checkout page.
6. Extract the `submit_order` nonce from `sepay_vars` (using `browser_eval`).
7. Use `http_request` to call `sepay_check_order_status` with `orderID=100` and the extracted nonce.
8. Confirm the response contains order status and download links.
Wait, what if the nonce is only on the Thank You page?
The Thank
Summary
The SePay Gateway plugin for WordPress (<= 1.1.20) is vulnerable to unauthenticated information exposure via the 'sepay_check_order_status' AJAX action. Attackers can exploit this by using a generic, publicly available nonce to query sensitive order details, including status and download links for purchased products, for any valid Order ID.
Vulnerable Code
// sepay-gateway.php add_action('wp_ajax_nopriv_sepay_check_order_status', 'sepay_check_order_status'); add_action('wp_ajax_sepay_check_order_status', 'sepay_check_order_status'); // ... function sepay_check_order_status() { if (!isset($_POST['order_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['order_nonce'])), 'submit_order')) { wp_die(); } if (!isset($_POST['orderID'])) { wp_die(); } $order_id = intval($_POST['orderID']); $order = wc_get_order($order_id); --- // includes/class-wc-gateway-sepay.php line 767 'order_nonce' => wp_create_nonce('submit_order'),
Security Fix
@@ -764,10 +771,27 @@ 'account_number' => $account_number, 'remark' => $this->get_remark($order_id), 'amount' => $order->get_total(), - 'order_nonce' => wp_create_nonce('submit_order'), + 'order_nonce' => wp_create_nonce('sepay_check_order_' . $order->get_order_key()), 'order_id' => $order_id, + 'order_key' => $order->get_order_key(), 'download_mode' => $this->get_option('download_mode'), @@ -180,16 +180,32 @@ function sepay_check_order_status() { - if (!isset($_POST['order_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['order_nonce'])), 'submit_order')) { - wp_die(); - } - if (!isset($_POST['orderID'])) { - wp_die(); + wp_send_json(['status' => false], 400); } - $order_id = intval($_POST['orderID']); + $order_id = absint($_POST['orderID']); $order = wc_get_order($order_id); + + if (!$order) { + wp_send_json(['status' => false], 404); + } + + $nonce = isset($_POST['order_nonce']) ? sanitize_text_field(wp_unslash($_POST['order_nonce'])) : ''; + if (!wp_verify_nonce($nonce, 'sepay_check_order_' . $order->get_order_key())) { + wp_send_json(['status' => false], 403); + } + + $supplied_key = isset($_POST['order_key']) ? sanitize_text_field(wp_unslash($_POST['order_key'])) : '';
Exploit Outline
1. Access the WooCommerce checkout page as an unauthenticated visitor to locate the 'sepay_vars' JavaScript object containing the 'submit_order' nonce. 2. Identify target Order IDs (e.g., through enumeration if IDs are sequential). 3. Craft a POST request to '/wp-admin/admin-ajax.php' with 'action=sepay_check_order_status', 'orderID=[TARGET_ID]', and 'order_nonce=[EXTRACTED_NONCE]'. 4. Observe the JSON response, which includes the order's fulfillment status and direct download URLs for any digital products associated with the order.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.