CVE-2025-14757

Cost Calculator Builder <= 3.6.9 - Missing Authorization to Unauthenticated Payment Status Bypass

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
3.6.10
Patched in
1d
Time to patch

Description

The Cost Calculator Builder plugin for WordPress is vulnerable to Unauthenticated Payment Status Bypass in all versions up to, and including, 3.6.9 only when used in combination with Cost Calculator Builder PRO. This is due to the complete_payment AJAX action being registered via wp_ajax_nopriv, making it accessible to unauthenticated users, and the complete() function only verifying a nonce without checking user capabilities or order ownership. Since nonces are exposed to all visitors via window.ccb_nonces in the page source, any unauthenticated attacker can mark any order's payment status as "completed" without actual payment.

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<=3.6.9
PublishedJanuary 15, 2026
Last updatedJanuary 16, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the methodology for exploiting CVE-2025-14757, a Missing Authorization vulnerability in the Cost Calculator Builder plugin. ### 1. Vulnerability Summary The Cost Calculator Builder plugin (specifically when paired with the PRO version) registers an AJAX action `complete_…

Show full research plan

This research plan outlines the methodology for exploiting CVE-2025-14757, a Missing Authorization vulnerability in the Cost Calculator Builder plugin.

1. Vulnerability Summary

The Cost Calculator Builder plugin (specifically when paired with the PRO version) registers an AJAX action complete_payment via wp_ajax_nopriv_complete_payment, making it accessible to unauthenticated users. The handler function for this action (likely complete() in a payment-related class) verifies a WordPress nonce but fails to perform any capability checks or verify if the requester has ownership of the order. Because the required nonce is globally exposed in the frontend source code via the ccb_nonces JavaScript object, any visitor can mark any order as "completed" without performing an actual payment.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • AJAX Action: complete_payment
  • HTTP Method: POST
  • Authentication: None (Unauthenticated)
  • Vulnerable Parameter: order_id (inferred) or id (inferred)
  • Nonce Parameter: nonce (referenced in the description)
  • Preconditions:
    1. Cost Calculator Builder (Base) <= 3.6.9 installed.
    2. Cost Calculator Builder PRO installed and active.
    3. At least one order must exist in the system (e.g., in "pending" status).

3. Code Flow (Inferred)

  1. Entry: An unauthenticated POST request is sent to admin-ajax.php?action=complete_payment.
  2. Hook: WordPress matches the wp_ajax_nopriv_complete_payment hook to a handler function (likely in an Orders or Payment controller).
  3. Nonce Check: The handler calls check_ajax_referer( 'ccb_nonce', 'nonce' ) (action string inferred). This passes because the nonce is publicly available.
  4. Authorization Failure: The code proceeds to update the order status without calling current_user_can() or checking if the order belongs to the current session/user.
  5. State Change: The handler calls a database update (likely via $wpdb) to change the order's status column to completed or paid.

4. Nonce Acquisition Strategy

The vulnerability description explicitly identifies the nonce source.

  1. Identify Page: Find a page containing a Cost Calculator (usually uses shortcode [cost_calculator] or [cc_builder]).
  2. Navigate: Use browser_navigate to visit that page.
  3. Extract: Use browser_eval to extract the nonce from the localized script object.
    • JavaScript Command: window.ccb_nonces?.ccb_nonce (or similar key within the ccb_nonces object).
    • Localization Key: ccb_nonces (from source).

5. Exploitation Strategy

  1. Setup Environment: Ensure both CCB and CCB PRO are active.
  2. Create Target Order: Use the frontend calculator to submit a "booking" or "order" that results in a "Pending" status. Note the Order ID.
  3. Retrieve Nonce: Navigate to any page with the calculator and extract the nonce from window.ccb_nonces.
  4. Craft Exploit Request:
    • URL: http://localhost:8080/wp-admin/admin-ajax.php
    • Method: POST
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body: action=complete_payment&nonce=[EXTRACTED_NONCE]&order_id=[TARGET_ORDER_ID] (Note: parameter names like order_id should be verified via grep in the plugin source if available).
  5. Execute: Send the request using http_request.

6. Test Data Setup

  1. Calculator Creation: Create a simple calculator with a total and a "Submit" or "Payment" button.
  2. Shortcode Placement:
    wp post create --post_type=page --post_title="Payment Test" --post_status=publish --post_content='[cost_calculator id="1"]'
    
  3. Order Generation: Navigate to the page, fill out the calculator, and submit it to generate a "Pending" order.
  4. Order ID Discovery:
    # Check the database for the last created order ID and its status
    wp db query "SELECT id, status FROM wp_ccb_orders ORDER BY id DESC LIMIT 1"
    

7. Expected Results

  • HTTP Response: A success code (e.g., 200 OK) and potentially a JSON response like {"success": true} or 1.
  • System Impact: The order status in the WordPress database for the specified order_id transitions from pending (or similar) to completed.

8. Verification Steps

After sending the AJAX request, verify the database state using WP-CLI:

# Verify the status change
wp db query "SELECT id, status FROM wp_ccb_orders WHERE id = [TARGET_ORDER_ID]"
  • Success Criteria: Status is "completed" or "paid".

9. Alternative Approaches

  • Parameter Guessing: If order_id is not the correct key, try id, order, or payment_id.
  • Action String Verification: If ccb_nonce is not the correct key in the ccb_nonces object, inspect the full object using browser_eval("window.ccb_nonces") to find the relevant key.
  • Database Inspection: If the table name wp_ccb_orders is incorrect, use wp db tables | grep ccb to find the correct table name for order tracking.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Cost Calculator Builder plugin for WordPress is vulnerable to an unauthenticated payment status bypass because it registers the complete_payment AJAX action for unauthenticated users. The handler function verifies a WordPress nonce but lacks any server-side authorization or order ownership checks, allowing attackers to manually transition orders to a completed status without payment.

Vulnerable Code

// Inferred registration of AJAX action in class constructor or init
add_action( 'wp_ajax_complete_payment', array( $this, 'complete' ) );
add_action( 'wp_ajax_nopriv_complete_payment', array( $this, 'complete' ) );

// Likely handler function in a payment or order class
public function complete() {
    // Nonce verification exists but the nonce is exposed on the frontend
    check_ajax_referer( 'ccb_nonce', 'nonce' );

    $order_id = isset( $_POST['order_id'] ) ? intval( $_POST['order_id'] ) : 0;
    if ( $order_id ) {
        // Vulnerability: No capability check (e.g., current_user_can) 
        // or verification that the order belongs to the current session user.
        $this->update_order_status( $order_id, 'completed' );
        wp_send_json_success();
    }
}

Security Fix

--- a/cost-calculator-builder/includes/classes/class-ccb-ajax.php
+++ b/cost-calculator-builder/includes/classes/class-ccb-ajax.php
@@ -1,5 +1,4 @@
 add_action( 'wp_ajax_complete_payment', array( $this, 'complete' ) );
-add_action( 'wp_ajax_nopriv_complete_payment', array( $this, 'complete' ) );
 
 public function complete() {
-    check_ajax_referer( 'ccb_nonce', 'nonce' );
+    check_ajax_referer( 'ccb_nonce', 'nonce' );
+
+    if ( ! current_user_can( 'manage_options' ) ) {
+        wp_send_json_error( array( 'message' => 'Unauthorized' ) );
+        return;
+    }

Exploit Outline

1. Locate a page on the target WordPress site that contains a Cost Calculator form (often identified by shortcodes like [cost_calculator]). 2. View the page source and inspect the global JavaScript object 'window.ccb_nonces' to extract the valid 'ccb_nonce' value. 3. Identify a target 'order_id' that is currently in a 'pending' or 'unpaid' state. 4. Send an unauthenticated HTTP POST request to '/wp-admin/admin-ajax.php' with the following parameters: action=complete_payment, nonce=[EXTRACTED_NONCE], and order_id=[TARGET_ORDER_ID]. 5. The server will process the request and update the status of the specified order to 'completed' in the database without any actual payment transaction occurring.

Check if your site is affected.

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