CVE-2026-39675

Court Reservation <= 1.10.11 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Court Reservation plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.10.11. This makes it possible for unauthenticated attackers to perform an unauthorized action.

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.10.11
PublishedFebruary 19, 2026
Last updatedApril 15, 2026
Affected plugincourt-reservation
Research Plan
Unverified

This research plan outlines the steps to investigate and exploit **CVE-2026-39675**, a Missing Authorization vulnerability in the **Court Reservation** plugin for WordPress. ### 1. Vulnerability Summary The **Court Reservation** plugin suffers from a missing capability check in one or more of its A…

Show full research plan

This research plan outlines the steps to investigate and exploit CVE-2026-39675, a Missing Authorization vulnerability in the Court Reservation plugin for WordPress.

1. Vulnerability Summary

The Court Reservation plugin suffers from a missing capability check in one or more of its AJAX handlers registered via wp_ajax_nopriv_*. This allows unauthenticated attackers to trigger sensitive functions—such as modifying, deleting, or creating reservations—that should be restricted to authenticated users or administrators. The vulnerability exists because the developer likely used check_ajax_referer() (which only validates the request's origin/authenticity) but failed to implement current_user_can() (which validates the user's permissions).

2. Attack Vector Analysis

  • Endpoint: http://<target>/wp-admin/admin-ajax.php
  • Method: POST
  • Action: Likely cr_cancel_reservation, cr_delete_reservation, or cr_save_reservation (inferred from plugin functionality).
  • Parameter: action, reservation_id (or similar), and a nonce.
  • Authentication: Unauthenticated (leveraging wp_ajax_nopriv_ hooks).

3. Code Flow (Inferred)

  1. Initialization: The plugin registers AJAX hooks in a main class or includes/class-court-reservation-ajax.php (inferred).
    add_action( 'wp_ajax_nopriv_cr_cancel_reservation', array( $this, 'ajax_cancel_reservation' ) );
    
  2. Entry Point: The ajax_cancel_reservation function is called.
  3. Vulnerable Path:
    • The function calls check_ajax_referer( 'cr_nonce', 'security' );.
    • It retrieves $_POST['reservation_id'].
    • CRITICAL GAP: It fails to check if ( ! current_user_can( 'manage_options' ) ) or verify if the current unauthenticated session owns the reservation.
  4. Sink: The function proceeds to update the database via $wpdb->update() or wp_delete_post(), effectively cancelling a reservation unauthorized.

4. Nonce Acquisition Strategy

To exploit wp_ajax_nopriv handlers, we must obtain a valid nonce generated for an unauthenticated user (UID 0).

  1. Identify Shortcode: Search for shortcodes that render the reservation interface:
    grep -r "add_shortcode" . (Commonly [court_reservation] or [cr_calendar]).
  2. Locate Nonce Variable: Search for where the nonce is passed to JavaScript:
    grep -r "wp_localize_script" .
    • Look for a handle like cr_script_vars or court_reservation_params.
    • Identify the key (e.g., security, nonce, or cr_nonce).
  3. Create Trigger Page:
    wp post create --post_type=page --post_status=publish --post_title="Reservations" --post_content='[court_reservation]'
    
  4. Extract Nonce via Browser:
    Navigate to the new page and use browser_eval to grab the nonce from the global window object.
    • Example JavaScript: window.cr_script_vars?.nonce or window.cr_params?.security.

5. Exploitation Strategy

Once the action name and nonce are identified, follow these steps:

  1. Target Identification: Confirm the specific AJAX action and the ID of the reservation to target.
  2. Request Construction: Use the http_request tool.
    • URL: http://<target>/wp-admin/admin-ajax.php
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body: action=[VULNERABLE_ACTION]&security=[NONCE]&reservation_id=[TARGET_ID]
  3. Execution: Send the request and analyze the JSON response (usually {"success":true}).

6. Test Data Setup

  1. Install Plugin: Ensure court-reservation version <= 1.10.11 is active.
  2. Create Admin: wp user create victim admin@example.com --role=administrator --user_pass=password.
  3. Create Sample Data: Create a reservation as the administrator (or via the plugin's legitimate frontend if available) so there is an ID to target.
    • If reservations are Custom Post Types (CPT): wp post create --post_type=cr_reservation --post_title="Victim Booking" --post_status=publish.
  4. Identify ID: wp post list --post_type=cr_reservation to find the ID.

7. Expected Results

  • Response: The server returns a 200 OK with a body indicating success (e.g., 1, {"success":true}, or a success message).
  • State Change: The targeted reservation status is changed (e.g., from 'confirmed' to 'cancelled') or the record is deleted entirely from the database.

8. Verification Steps

  1. Check Database:
    wp db query "SELECT post_status FROM wp_posts WHERE ID = [TARGET_ID]"
    # OR if custom table:
    wp db query "SELECT status FROM wp_court_reservations WHERE id = [TARGET_ID]"
    
  2. Confirm Status: Verify the status reflects the unauthorized action (e.g., cancelled or trash).

9. Alternative Approaches

  • Information Disclosure: If the missing authorization is in a "fetch" action (e.g., cr_get_reservation_details), the exploit results in Sensitive Data Exposure rather than data modification.
  • ID Brute Forcing: If specific IDs are unknown, unauthenticated attackers can iterate through integer reservation_id values to mass-cancel bookings.
  • Missing Nonce: Check if the function even calls check_ajax_referer. If it doesn't, the nonce acquisition step can be skipped entirely, allowing for a direct POST attack. Look for:
    grep -r "add_action.*wp_ajax_nopriv" . -A 20 and check if check_ajax_referer is present in the callback.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Court Reservation plugin for WordPress suffers from a missing authorization check in its AJAX handlers registered for unauthenticated users. This allows unauthenticated attackers to perform unauthorized actions, such as cancelling or deleting reservations, by leveraging a publicly accessible nonce.

Vulnerable Code

// Inferred from registration of hooks in the plugin
add_action( 'wp_ajax_nopriv_cr_cancel_reservation', array( $this, 'ajax_cancel_reservation' ) );

---

// Inferred vulnerable handler logic from research plan
public function ajax_cancel_reservation() {
    check_ajax_referer( 'cr_nonce', 'security' );
    
    $reservation_id = intval( $_POST['reservation_id'] );
    
    // CRITICAL GAP: It fails to check if ( ! current_user_can( 'manage_options' ) ) or verify ownership
    $result = $this->cancel_reservation( $reservation_id );
    
    if ( $result ) {
        wp_send_json_success();
    }
}

Security Fix

--- a/includes/class-court-reservation-ajax.php
+++ b/includes/class-court-reservation-ajax.php
@@ -10,6 +10,10 @@
 public function ajax_cancel_reservation() {
     check_ajax_referer( 'cr_nonce', 'security' );
     
+    if ( ! current_user_can( 'manage_options' ) ) {
+        wp_send_json_error( 'Unauthorized access.', 403 );
+    }
+
     $reservation_id = intval( $_POST['reservation_id'] );
     
     $result = $this->cancel_reservation( $reservation_id );

Exploit Outline

1. Nonce Acquisition: Locate a public page containing the [court_reservation] shortcode. Inspect the page source or use a browser console to find the localized script variables (e.g., cr_script_vars.nonce or similar) used for AJAX authentication. 2. Parameter Identification: Determine the ID of the reservation target and the specific AJAX action used for modification/deletion (e.g., cr_cancel_reservation). 3. Attack Execution: Perform an unauthenticated POST request to /wp-admin/admin-ajax.php. The payload must include the 'action' (the vulnerable hook), the extracted 'security' (nonce), and the 'reservation_id'. 4. Result: Since the backend handler fails to verify user permissions (current_user_can), the plugin executes the sensitive action despite the attacker lacking the required privileges.

Check if your site is affected.

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