Appointment Booking Calendar <= 1.4.4 - Authenticated (Author+) Stored Cross-Site Scripting via Custom Booking Field Label
Description
The Appointment Booking Calendar plugin for WordPress is vulnerable to Stored Cross-Site Scripting via custom booking field labels in all versions up to, and including, 1.4.4 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with Author-level access and above, 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:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.4.4What Changed in the Fix
Changes introduced in v1.4.5
Source Code
WordPress.org SVNThis research plan outlines the technical steps to exploit **CVE-2026-1856**, a Stored Cross-Site Scripting (XSS) vulnerability in the **Appointment Booking Calendar** plugin (version <= 1.4.4). ### 1. Vulnerability Summary The vulnerability exists in how the plugin handles custom booking field lab…
Show full research plan
This research plan outlines the technical steps to exploit CVE-2026-1856, a Stored Cross-Site Scripting (XSS) vulnerability in the Appointment Booking Calendar plugin (version <= 1.4.4).
1. Vulnerability Summary
The vulnerability exists in how the plugin handles custom booking field labels. While the plugin uses sanitize_text_field() during the saving process in includes/save-service.php, this function only strips HTML tags (like <script>) and does not escape quotes or other characters that can be used for attribute injection. Furthermore, the frontend JavaScript (assets/js/booking.js) and PHP rendering logic (includes/render-booking-inline.php) do not sufficiently escape these labels when constructing the booking form's HTML. An attacker with Author-level permissions can inject a payload into a field label that executes arbitrary JavaScript in the context of any user viewing the booking form.
2. Attack Vector Analysis
- Vulnerable Endpoint: WordPress Admin Post Editor (
wp-admin/post.php). - Vulnerable Action: Saving or updating a
creavibc_servicepost type. - Vulnerable Parameter:
creavibc_custom_fields[label][]. - Authentication Requirement: Author-level access or higher.
- Preconditions: The attacker must have permission to create or edit
creavibc_serviceposts.
3. Code Flow
- **Input
Summary
The Appointment Booking Calendar plugin is vulnerable to Stored Cross-Site Scripting via custom booking field labels due to a failure to escape labels when rendering them in the frontend booking form. Authenticated attackers with Author-level permissions or higher can inject arbitrary JavaScript that executes whenever a user views the affected booking service form.
Vulnerable Code
// includes/save-service.php line 133 $custom_fields = isset($_POST['creavibc_custom_fields']) ? wp_unslash($_POST['creavibc_custom_fields']) : []; $labels = isset($custom_fields['label']) ? array_map('sanitize_text_field', $custom_fields['label']) : []; $types = isset($custom_fields['type']) ? array_map('sanitize_text_field', $custom_fields['type']) : []; $required = isset($custom_fields['required']) ? array_map('sanitize_text_field', $custom_fields['required']) : []; --- // assets/js/booking.js line 782 if (Array.isArray(form.custom)) { form.custom.forEach((field, i) => { //const label = field.label || `Field ${i + 1}`; const label = field.label || sprintf( __( 'Field %d', CBS_DOMAIN ), i + 1 ); const type = field.type || 'text'; const required = field.required ? 'required' : ''; html += `<label>${label}${required ? ' <span class="creavibc-required">*</span>' : ''}`; html += type === 'textarea' ? `<textarea id="creavibc-custom-${i}-${serviceId}" data-label="${label}" ${required}></textarea>` : `<input type="text" id="creavibc-custom-${i}-${serviceId}" data-label="${label}" ${required}>`; html += `</label>`; }); }
Security Fix
@@ -779,20 +779,21 @@ } - if (Array.isArray(form.custom)) { - form.custom.forEach((field, i) => { - //const label = field.label || `Field ${i + 1}`; - const label = field.label || sprintf( __( 'Field %d', CBS_DOMAIN ), i + 1 ); - - const type = field.type || 'text'; - const required = field.required ? 'required' : ''; - html += `<label>${label}${required ? ' <span class="creavibc-required">*</span>' : ''}`; - html += type === 'textarea' - ? `<textarea id="creavibc-custom-${i}-${serviceId}" data-label="${label}" ${required}></textarea>` - : `<input type="text" id="creavibc-custom-${i}-${serviceId}" data-label="${label}" ${required}>`; - html += `</label>`; - }); - } + if (Array.isArray(form.custom)) { + form.custom.forEach((field, i) => { + //const label = field.label || `Field ${i + 1}`; + const label = String(field.label || sprintf( __( 'Field %d', CBS_DOMAIN ), i + 1 )); + const safeLabel = creavibcEscapeHtml(label); + + const type = field.type || 'text'; + const required = field.required ? 'required' : ''; + html += `<label>${safeLabel}${required ? ' <span class="creavibc-required">*</span>' : ''}`; + html += type === 'textarea' + ? `<textarea id="creavibc-custom-${i}-${serviceId}" data-label="${safeLabel}" ${required}></textarea>` + : `<input type="text" id="creavibc-custom-${i}-${serviceId}" data-label="${safeLabel}" ${required}>`; + html += `</label>`; + }); + }
Exploit Outline
1. Authenticate with an account having at least Author-level permissions. 2. Navigate to the Service Editor (wp-admin/post-new.php?post_type=creavibc_service). 3. Locate the 'Form Fields' settings metabox. 4. Add a new custom field and input an XSS payload into the 'Label' field (e.g., "><img src=x onerror=alert(1)>). 5. Save or publish the service. 6. Embed the booking service on a page using the provided shortcode or view the service's frontend popup. 7. When the JavaScript in booking.js renders the form, the unsanitized label will break out of the HTML attribute context or label tag and execute the payload.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.