CVE-2026-4911

Booking Package <= 1.7.06 - Unauthenticated Price Manipulation via 'amount' Parameter

mediumExternal Control of Assumed-Immutable Web Parameter
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
1.7.07
Patched in
1d
Time to patch

Description

The Booking Package plugin for WordPress is vulnerable to Price Manipulation in versions up to, and including, 1.7.06 This is due to the intentForStripe() function passing user-controlled $_POST['amount'] directly to the Stripe PaymentIntent API without validation, and the commitStripe() function ignoring the server-calculated amount when confirming the payment. While the server correctly calculates the booking cost via getAmount() based on services, guests, taxes, and coupons, this calculated amount is never validated against or used to update the PaymentIntent because the critical code in CreditCard.php that would include the calculated amount in the PaymentIntent update is commented out. This makes it possible for unauthenticated attackers to book services at arbitrary prices (e.g., $0.01 instead of $500.00) by manipulating the amount parameter during PaymentIntent creation and completing the booking with the fraudulent 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<=1.7.06
PublishedApril 27, 2026
Last updatedApril 28, 2026
Affected pluginbooking-package

What Changed in the Fix

Changes introduced in v1.7.07

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-4911 (Booking Package Price Manipulation) ## 1. Vulnerability Summary The **Booking Package** plugin (<= 1.7.06) contains a critical flaw in its Stripe payment integration. The plugin allows the client to specify the payment amount during the creation of a Str…

Show full research plan

Exploitation Research Plan: CVE-2026-4911 (Booking Package Price Manipulation)

1. Vulnerability Summary

The Booking Package plugin (<= 1.7.06) contains a critical flaw in its Stripe payment integration. The plugin allows the client to specify the payment amount during the creation of a Stripe PaymentIntent via the intentForStripe() function without validating it against the server-side calculated cost of the booking. Furthermore, the commitStripe() function, which finalizes the booking after payment confirmation, fails to verify that the amount actually paid matches the required cost for the selected services, guests, and taxes. This is because the validation code in lib/CreditCard.php was explicitly commented out in the vulnerable versions.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • Action: package_app_public_action (registered via BOOKING_PACKAGE class in index.php)
  • Internal Action (Sub-type): intentForStripe and commitStripe (passed in the POST body)
  • Vulnerable Parameter: amount (used during intentForStripe)
  • Authentication: Unauthenticated. The AJAX action is registered via wp_ajax_nopriv_package_app_public_action.
  • Preconditions:
    • A booking calendar must be configured and published via shortcode.
    • At least one service with a cost > $0.00 must exist.
    • Stripe payment must be enabled (even in test mode).

3. Code Flow

  1. Entry Point: The browser sends an AJAX POST request to admin-ajax.php with action=package_app_public_action.
  2. Routing: In index.php, the $action_public hook triggers a handler (likely within a dynamically included class or handled via a switch in index.php or Schedule.php).
  3. Intent Creation (intentForStripe):
    • The request reaches lib/CreditCard.php -> intentForStripe().
    • It reads $_POST['amount'].
    • It calls the Stripe API to create a PaymentIntent with this user-supplied amount.
    • Vulnerability: There is no check comparing $_POST['amount'] to the result of getAmount().
  4. Finalization (commitStripe):
    • After the user "pays," the browser calls commitStripe to finalize the booking.
    • commitStripe() verifies with Stripe that the PaymentIntent ID is "succeeded".
    • Vulnerability: It fails to check if the amount in the successful PaymentIntent matches the actual cost calculated by getAmount().

4. Nonce Acquisition Strategy

The plugin localizes a reservation_info object into the page containing the booking shortcode.

  1. Shortcode Identification: The plugin uses [booking_package id=X].
  2. Page Creation: Use WP-CLI to create a page with a valid calendar ID (usually 1 for the first calendar).
    wp post create --post_type=page --post_status=publish --post_title="Booking" --post_content='[booking_package id=1]'
    
  3. Extraction:
    • Navigate to the newly created page.
    • Use browser_eval to extract the required identifiers from the global reservation_info object.
    • Identifiers to extract:
      • window.reservation_info.nonce
      • window.reservation_info.action (should be package_app_public_action)
      • window.reservation_info.accountKey (the calendar ID)

5. Exploitation Strategy

The goal is to book a expensive service for $0.01 (1 cent).

Step 1: Create Stripe Intent with Manipulated Amount

  • Method: POST
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Body (URL-encoded):
    • action: package_app_public_action
    • nonce: [EXTRACTED_NONCE]
    • type: intentForStripe
    • amount: 1 (Representing 1 cent, or 0.01 in most currencies)
    • currency: usd (or as per calendar settings)
    • calendar_id: 1
  • Expected Response: A JSON object containing a client_secret from Stripe.

Step 2: "Payment" (Simulated)

In a real attack, the attacker would use the client_secret to complete the payment via Stripe's JS SDK using a test card or a real card for the $0.01. For the PoC, since we cannot interact with Stripe's actual backend in an isolated environment, we look for the transition to commitStripe.

Step 3: Finalize Booking

  • Method: POST
  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Body (URL-encoded):
    • action: package_app_public_action
    • nonce: [EXTRACTED_NONCE]
    • type: commitStripe
    • payment_intent_id: [ID_FROM_STEP_1]
    • booking_data: [JSON_DATA_OF_BOOKING]
  • Note: In the vulnerable version, commitStripe will see the PaymentIntent is valid for the amount ($0.01) and finalize the booking.

6. Test Data Setup

  1. Create Calendar: Ensure a calendar exists (Calendar ID 1).
  2. Create Service: Add a service to the calendar with a high price.
    # Use SQL to verify/insert a service with price 10000 (cents)
    wp db query "UPDATE wp_booking_package_services SET cost = 10000 WHERE id = 1;"
    
  3. Enable Stripe: Set a dummy Stripe key to satisfy plugin checks.
    wp option update booking_package_stripe_secret_key "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
    wp option update booking_package_stripe_publishable_key "pk_test_TYooMQauvdEDq54NiTphI7jx"
    

7. Expected Results

  • The request to intentForStripe should return a success status with a Stripe client_secret, even though the amount provided (1) is significantly lower than the service cost (10000).
  • The plugin should not return an error stating "Invalid amount" or "Price mismatch".

8. Verification Steps

After the exploit attempts, check the booking records in the database:

# Check the latest booking amount
wp db query "SELECT * FROM wp_booking_package_bookings ORDER BY id DESC LIMIT 1;"

Confirm that the total_price or recorded payment in the database reflects the manipulated price ($0.01) while the service provided was the $100.00 service.

9. Alternative Approaches

If intentForStripe requires more complex booking_data, capture a legitimate request first using the browser_navigate and network monitoring.

  1. Navigate to the booking page.
  2. Fill out the form normally.
  3. Use browser_eval to intercept the call to booking_Package.intentForStripe or monitor the fetch/XHR requests.
  4. Replay the request with the amount modified to 1.

Check if your site is affected.

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