Appointment Hour Booking – Booking Calendar <= 1.5.60 - Authenticated (Administrator+) Stored Cross-Site Scripting via 'Min/Max Length' Field Configuration
Description
The Appointment Hour Booking – Booking Calendar plugin for WordPress is vulnerable to Stored Cross-Site Scripting via form field configuration parameters in all versions up to, and including, 1.5.60 due to insufficient input sanitization and output escaping on the 'Min length/characters' and 'Max length/characters' field configuration values. This makes it possible for authenticated attackers, with administrator-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses the form builder interface. This only affects multi-site installations and installations where unfiltered_html has been disabled.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.5.60Source Code
WordPress.org SVN# Research Plan: CVE-2026-1083 - Stored XSS in Appointment Hour Booking ## 1. Vulnerability Summary The **Appointment Hour Booking** plugin (<= 1.5.60) contains a stored cross-site scripting (XSS) vulnerability in the form builder interface. The plugin fails to sufficiently sanitize or escape the `…
Show full research plan
Research Plan: CVE-2026-1083 - Stored XSS in Appointment Hour Booking
1. Vulnerability Summary
The Appointment Hour Booking plugin (<= 1.5.60) contains a stored cross-site scripting (XSS) vulnerability in the form builder interface. The plugin fails to sufficiently sanitize or escape the Min length/characters and Max length/characters configuration values for form fields. When an administrator (or attacker with admin-level access in a multisite/restricted environment) saves a form configuration containing a malicious payload in these fields, the script is stored in the database. The payload then executes when any user (typically an administrator) accesses the form builder to edit that specific form.
2. Attack Vector Analysis
- Vulnerable Endpoint: The administrative form builder page, typically accessed via
wp-admin/admin.php?page=cp_appbooking. - Vulnerable Action: Saving form configurations. This is usually a POST request to the same page or an AJAX action.
- Vulnerable Parameters: The payload is injected into the
minlengthormaxlengthproperties within the serialized or JSON-encoded form structure. - Authentication: Requires Administrator-level privileges (
manage_options). - Preconditions: In a standard single-site installation, admins have the
unfiltered_htmlcapability, making this vulnerability technically "intended behavior" for them. However, in WordPress Multisite or installations whereDISALLOW_UNFILTERED_HTMLis defined as true, this represents a privilege escalation/security bypass.
3. Code Flow (Inferred)
- Entry Point: The administrator navigates to the "Appointment Hour Booking" menu and selects "Edit" on a calendar/form.
- Data Submission: The user modifies a field (e.g., a "Single Line Text" field) and sets a "Min Length" value.
- Processing: When "Save Changes" is clicked, a POST request is sent. The plugin handles this in the admin initialization (likely
admin_initor the menu page callback). - Storage: The plugin processes the
form_structureparameter and saves it to the database (likely in thewp_optionstable under a key likeCP_APPBOOKING_ID1_STRUCor within a custom tablewp_cp_appbooking_calendars). - Sink: When the form builder is reloaded, the plugin retrieves the structure and outputs it into the page as part of a JavaScript object (to initialize the UI) or within HTML attributes. Due to lack of
esc_attr()orjson_encode()with proper flags, the payload breaks out of the context.
4. Nonce Acquisition Strategy
The form builder uses nonces for security. Since we are acting as an authenticated administrator, we can extract the nonce from the admin interface.
- Identify Shortcode: The plugin's main functionality is triggered by the
[CP_APPBOOKING_ID=1](inferred) shortcode. - Create Setup Page:
wp post create --post_type=page --post_status=publish --post_title="Booking" --post_content='[CP_APPBOOKING_ID=1]' - Extract Nonce via Browser:
Navigate to the admin page:/wp-admin/admin.php?page=cp_appbooking.
The nonce is typically found in the HTML source or a JS variable.
JS Variable (Inferred):window.cp_appbooking_params?.nonceor a hidden input namedcp_appbooking_nonce.
Extraction Command:browser_eval("document.querySelector('input[name=\"_wpnonce\"]')?.value || document.querySelector('#cp_appbooking_nonce')?.value")
5. Exploitation Strategy
Step 1: Analyze the Form Structure
First, we must understand how the plugin sends the form structure. It is usually a JSON string in a POST parameter named form_structure.
Step 2: Craft the Payload
The payload must break out of a JSON string or an HTML attribute.
Payload: 123"><script>alert(document.domain)</script>
Step 3: Send the Malicious Update
We will perform an http_request as the Admin to update the form.
HTTP Request (Example):
- Method: POST
- URL:
http://localhost:8080/wp-admin/admin.php?page=cp_appbooking&item=1 - Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
action:save_form(inferred)_wpnonce:[EXTRACTED_NONCE]form_structure:[{"name":"fieldname1","type":"text","minlength":"123\"><script>alert(document.domain)</script>","maxlength":"10"}](Simplified JSON example)
Step 4: Trigger the XSS
Navigate to the form editor page:http://localhost:8080/wp-admin/admin.php?page=cp_appbooking&item=1
The payload should execute upon page load as the builder renders the field settings.
6. Test Data Setup
- Install and activate "Appointment Hour Booking" version 1.5.60.
- Ensure an administrator user exists.
- Optional: Disable
unfiltered_htmlto simulate a restricted environment:wp config set DISALLOW_UNFILTERED_HTML true --raw - Create at least one booking calendar (usually one is created by default on install).
7. Expected Results
- The POST request to save the form should return a 200 OK or a 302 redirect.
- Upon navigating to the edit page for that form, a JavaScript alert box displaying the document domain should appear.
- The page source will reveal the unescaped string:
minlength="123"><script>alert(document.domain)</script>".
8. Verification Steps
- Verify Storage via CLI:
wp db query "SELECT * FROM wp_options WHERE option_name LIKE 'CP_APPBOOKING_%'"(Check if payload is present in the option value).
OR, if using a custom table:wp db query "SELECT * FROM wp_cp_appbooking_calendars" - Verify Execution: Use
browser_navigateto the admin page and check for the presence of the script in the DOM or the execution of the alert.
9. Alternative Approaches
- Property Injection: If the plugin uses
json_encodebut not on the server-side rendering of the length fields, try different breakout characters like"or\u0022. - Shortcode Injection: If the XSS doesn't trigger in the admin backend but does on the frontend, check the page where the
[CP_APPBOOKING]shortcode is placed. The vulnerability might manifest when the frontend JS initializes the validation rules using the storedminlengthproperty.
Summary
The Appointment Hour Booking – Booking Calendar plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) in versions up to 1.5.60 due to insufficient sanitization and escaping of the 'Min length/characters' and 'Max length/characters' field settings. Authenticated administrators can inject malicious scripts into these fields, which execute when the form builder interface is loaded by any user. This is particularly critical in Multisite environments or where unfiltered_html is disabled.
Exploit Outline
1. Log in to the WordPress admin dashboard as an administrator. 2. Navigate to the Appointment Hour Booking plugin and edit an existing calendar form. 3. Add or edit a form field (such as a 'Single Line Text' field) to access its configuration attributes. 4. Locate the 'Min length/characters' or 'Max length/characters' input fields. 5. Input a payload designed to break out of the HTML attribute context, such as: "><script>alert(document.domain)</script> 6. Save the form configuration. 7. The payload is stored in the database and triggers a stored XSS attack whenever an administrator re-opens the form builder to edit that specific form.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.