VikBooking Hotel Booking Engine & PMS <= 1.8.8 - Unauthenticated Stored Cross-Site Scripting via 'special_requests' Parameter
Description
The VikBooking Hotel Booking Engine & PMS plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'special_requests' 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:NTechnical Details
What Changed in the Fix
Changes introduced in v1.8.9
Source Code
WordPress.org SVNThis vulnerability is a **Stored Cross-Site Scripting (XSS)** vulnerability in the **VikBooking Hotel Booking Engine & PMS** plugin. It allows unauthenticated attackers to inject malicious scripts into the `special_requests` parameter during a room reservation. The payload is stored in the database …
Show full research plan
This vulnerability is a Stored Cross-Site Scripting (XSS) vulnerability in the VikBooking Hotel Booking Engine & PMS plugin. It allows unauthenticated attackers to inject malicious scripts into the special_requests parameter during a room reservation. The payload is stored in the database and executed when an administrator views the reservation details in the WordPress dashboard.
1. Vulnerability Summary
- Vulnerability: Stored Cross-Site Scripting (XSS)
- Vulnerable Parameter:
special_requests - Sink: The reservation details view in the admin dashboard (e.g.,
admin/helpers/widgets/booking_details.phpand reservation list views). - Root Cause: The plugin fails to sanitize the
special_requestsinput during order creation and fails to escape the output when rendering the booking details for administrators. - Authentication: None (Unauthenticated).
2. Attack Vector Analysis
- Endpoint: The front-end booking confirmation page (typically a page containing the
[vikbooking_search]or[vikbooking_room_details]shortcode). - Action: The final step of the booking process where customer details are submitted.
- Payload Location: The
special_requestsHTTP POST parameter. - Preconditions: At least one room must be published and available for booking to reach the checkout step.
3. Code Flow
The plugin follows a Joomla-inspired architecture adapted for WordPress.
- Entry Point (Front-end): A user initiates a booking. At the "Customer Details" or "Review" step, the
special_requestsfield is filled. - Processing: The request is typically handled by a front-end controller (e.g.,
VikBookingControllertasksaveorderorconfirm). - Storage: The
VBOModelReservation::save()(or similar method in the reservation model) receives the data. It uses$app->input->get()or$app->input->post->getString()with insufficient filtering. The raw or poorly sanitized string is inserted into the#__vikbooking_orderstable in thespecial_requestscolumn. - Sink (Admin): An administrator logs in and navigates to VikBooking > Reservations. When viewing the specific booking, the widget
VikBookingAdminWidgetBookingDetails(defined inadmin/helpers/widgets/booking_details.php) fetches the record:$q = $dbo->getQuery(true) ->select($dbo->qn('o') . '.*') ->from($dbo->qn('#__vikbooking_orders', 'o')); // ... filters ... $details = $dbo->loadAssoc(); - Execution: The
$details['special_requests']value is then echoed in an admin template without usingesc_html()or similar WordPress escaping functions, causing the script to execute in the administrator's browser.
4. Nonce Acquisition Strategy
VikBooking does not typically use standard WordPress nonces for the unauthenticated booking flow. Instead, it uses a session-based token (Joomla style).
- Identify Shortcode: Locate a page with the
[vikbooking_search]shortcode. - Navigate Flow: Use
browser_navigateto go through the booking steps (Search -> Select Room -> Customer Details). - Extract Token: On the "Customer Details" page, there is usually a hidden input field with a name that is a 32-character MD5 hash and a value of
1.- Example:
<input type="hidden" name="59d...a92" value="1" />.
- Example:
- JS Extraction: Use
browser_evalto find this token:// Find the hidden input that has a 32-char hex name and value '1' Array.from(document.querySelectorAll('input[type="hidden"]')) .find(i => /^[a-f0-9]{32}$/.test(i.name) && i.value === '1')?.name; - Bypass: If the plugin does not enforce
JSession::checkToken()for unauthenticated order saves (which is common to prevent session expiration issues during long checkouts), the request may succeed without it.
5. Exploitation Strategy
Step 1: Setup
- Ensure a room exists and is bookable.
- Note the room ID and a valid rate plan ID.
Step 2: Submission
The exploit involves mimicking the final POST request of the booking flow.
- URL:
http://localhost:8080/index.php?option=com_vikbooking&task=saveorder(or the URL of the booking page). - Method:
POST - Payload:
(Note: Parameter names may vary slightly; use Playwright to inspect the actual form on the Customer Details page).POST /wp-admin/admin-ajax.php?action=vikbooking_save_order HTTP/1.1 Content-Type: application/x-www-form-urlencoded idroom=1&idtar=1&checkin=2026-10-10&checkout=2026-10-12&first_name=Attacker&last_name=XSS&email=hacker@example.com&phone=123456&special_requests=<script>alert(document.domain)</script>&[TOKEN]=1
Step 3: Triggering
- Log in as Administrator.
- Navigate to
/wp-admin/admin.php?page=vikbooking&view=reservations. - Click on the "Edit" or "Details" icon for the new reservation.
6. Test Data Setup
- Create Room: Use WP-CLI or manual entry to ensure a room is available.
wp vikbooking room create --name="Luxury Suite" --units=5 --price=100(assuming CLI exists) or via DB.
- Publish Page: Create a page with the search shortcode.
wp post create --post_type=page --post_title="Book Now" --post_status=publish --post_content='[vikbooking_search]'
7. Expected Results
- The booking is successfully created.
- When the admin views the reservation in the dashboard, an alert box appearing with the domain name (or a fetch to a collaborator) confirms the XSS execution in the admin's session.
8. Verification Steps
After the HTTP request:
- Check DB: Verify the payload is stored exactly as sent.
wp db query "SELECT special_requests FROM wp_vikbooking_orders ORDER BY id DESC LIMIT 1" - Check Admin Page Render: Use
browser_navigateto the reservation details and check for the injected tag.
9. Alternative Approaches
- Quote Request: If the booking flow is complex, the
quotecontroller (admin/controllers/quote.php) might also be vulnerable if exposed to front-end users, using similar parameters. - Other Parameters: If
special_requestsis escaped, testfirst_nameorlast_name, as these are often stored in the sameorderstable and reflected in the same views.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.