In the shifting landscape of cyberspace, the emergence of security vulnerabilities is an inevitable phenomenon. A critical flaw, now identified as CVE-2023-34000 with a CVSS score of 7.5, has been detected in the widely used WooCommerce Stripe Gateway Plugin, prompting an urgent call to action for security professionals and site administrators alike.
This plugin, developed by WooCommerce and currently employed in over 900,000 active installations, is renowned for its streamlined capability to process payments directly on web and mobile stores. An inherent feature of this plugin allows customers to complete transactions within the online store environment, negating the need for an externally hosted checkout page.
However, beneath the plugin’s surface functionality lurks an Unauthenticated Insecure Direct Object Reference (IDOR) vulnerability. In its unpatched state, this flaw provides an unauthenticated user the opportunity to access highly sensitive Personally Identifiable Information (PII) of any WooCommerce order. This exposed data can include critical information such as a user’s name, email, and full residential address.
Tracing the root of this vulnerability brings us to the ‘javascript_params’ function within the plugin. The code within this function procures an order object through an ‘order_id’ variable. This variable is drawn from the query parameters and subsequently collates detailed data from the order object, including full user details and addresses. A glaring absence of order ownership checks within this function escalates the risk, enabling the return of the ‘order’ as an object.
public function javascript_params() {
global $wp;
$order_id = absint( get_query_var( 'order-pay' ) );
$stripe_params = [
'title' => $this->title,
'key' => $this->publishable_key,
'i18n_terms' => __( 'Please accept the terms and conditions first', 'woocommerce-gateway-stripe' ),
'i18n_required_fields' => __( 'Please fill in required checkout fields first', 'woocommerce-gateway-stripe' ),
'updateFailedOrderNonce' => wp_create_nonce( 'wc_stripe_update_failed_order_nonce' ),
'updatePaymentIntentNonce' => wp_create_nonce( 'wc_stripe_update_payment_intent_nonce' ),
'orderId' => $order_id,
'checkout_url' => WC_AJAX::get_endpoint( 'checkout' ),
];
// If we're on the pay page we need to pass stripe.js the address of the order.
if ( isset( $_GET['pay_for_order'] ) && 'true' === $_GET['pay_for_order'] ) { // wpcs: csrf ok.
$order_id = wc_clean( $wp->query_vars['order-pay'] ); // wpcs: csrf ok, sanitization ok, xss ok.
$order = wc_get_order( $order_id );
if ( is_a( $order, 'WC_Order' ) ) {
$stripe_params['billing_first_name'] = $order->get_billing_first_name();
$stripe_params['billing_last_name'] = $order->get_billing_last_name();
$stripe_params['billing_address_1'] = $order->get_billing_address_1();
$stripe_params['billing_address_2'] = $order->get_billing_address_2();
$stripe_params['billing_state'] = $order->get_billing_state();
$stripe_params['billing_city'] = $order->get_billing_city();
$stripe_params['billing_postcode'] = $order->get_billing_postcode();
$stripe_params['billing_country'] = $order->get_billing_country();
}
}
The ‘javascript_params’ variable, we discovered, could be invoked from the ‘payment_scripts’ function, which then returns a JavaScript object variable to the front-end through the ‘wp_localize_script’ function. The overall functionality triggers an order’s PII disclosure that is reflected back into the page source when the site’s front page is accessed.
public function payment_scripts() {
-----------------------------------------------------------------------------------------
wp_localize_script(
'woocommerce_stripe',
'wc_stripe_params',
apply_filters( 'wc_stripe_params', $this->javascript_params() )
);
Further investigation revealed a second instance of vulnerability located within the ‘payment_fields’ function, sharing a similar shortcoming with the ‘javascript_params’ function – the lack of order ownership verification. The outcome is the same: the user’s billing email and full name are exposed to the front-end.
public function payment_fields() {
global $wp;
$user = wp_get_current_user();
$display_tokenization = $this->supports( 'tokenization' ) && is_checkout() && $this->saved_cards;
$total = WC()->cart->total;
$user_email = '';
$description = $this->get_description();
$description = ! empty( $description ) ? $description : '';
$firstname = '';
$lastname = '';
// If paying from order, we need to get total from order not cart.
if ( isset( $_GET['pay_for_order'] ) && ! empty( $_GET['key'] ) ) { // wpcs: csrf ok.
$order = wc_get_order( wc_clean( $wp->query_vars['order-pay'] ) ); // wpcs: csrf ok, sanitization ok.
$total = $order->get_total();
$user_email = $order->get_billing_email();
} else {
if ( $user->ID ) {
$user_email = get_user_meta( $user->ID, 'billing_email', true );
$user_email = $user_email ? $user_email : $user->user_email;
}
}
if ( is_add_payment_method_page() ) {
$firstname = $user->user_firstname;
$lastname = $user->user_lastname;
}
ob_start();
echo '<div
id="stripe-payment-data"
data-email="' . esc_attr( $user_email ) . '"
data-full-name="' . esc_attr( $firstname . ' ' . $lastname ) . '"
data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '"
>';
To address the CVE-2023-34000 vulnerability, WooCommerce has rolled out a fix in version 7.4.1 with certain backported versions. Given the potential severity of the issue, site administrators and security professionals are encouraged to expedite their patching processes.