1. Vulnerability Background
This issue affects the Appointment Booking and Scheduling Calendar Plugin – WP Timetics for WordPress. In versions up to and including 1.0.36, the plugin suffers from missing authorization checks in both its REST API routing and appointment listing logic.
-
What is this vulnerability?
- A missing capability/permission check in REST route registration and appointment retrieval.
- REST API endpoints were registered with
permission_callbackreturningtrue, allowing unauthenticated or unauthorized access. - The front-end appointment listing queried all appointments without applying a visibility filter for non-admin users.
-
Why is it critical?
- Booking records often contain sensitive customer and scheduling data.
- Unauthorized access can expose all bookings on the site.
- Unauthorized modification can allow attackers to change or delete appointment details, disrupt operations, or manipulate booking status.
-
Affected systems/versions:
- WP Timetics plugin for WordPress
- All released versions up to and including 1.0.36
2. Technical Details
-
Root cause analysis
- In
core/bookings/api-booking.php, REST route permission callbacks were implemented as:'permission_callback' => function () { return true; }
- This effectively bypassed all REST API authorization for the affected endpoints.
- In
core/frontend/templates/meeting-list.php, appointment retrieval was performed as:$meetings = Appointment::all([ 'posts_per_page' => $limit ]);
- There was no capability check or visibility filter applied for non-admin users.
- In
-
Attack vector and exploitation conditions
- An attacker can perform unauthenticated HTTP requests against the plugin’s REST endpoints.
- If the plugin exposes booking endpoints through WordPress REST, a crafted request can retrieve or modify booking details.
- The front-end listing logic can expose booking records to users who should not have access, if the page is accessible.
- Exploitation requires only that the vulnerable plugin is installed and the endpoint is reachable; no valid WordPress credentials are necessary.
-
Security implications
- Confidential booking details can be disclosed.
- Booking records can be modified or potentially deleted.
- Business operations can be disrupted by tampering with schedules.
- Unauthorized disclosure may violate privacy and regulatory requirements.
3. Patch Analysis
-
What code changes were made?
core/frontend/templates/meeting-list.php- Old: queried all appointments unconditionally.
- New: builds
$argswith'posts_per_page' => $limit. - Adds
current_user_can('manage_options')check. - For non-admin users, adds
$args['visibility'] = 'enabled';. - Calls
Appointment::all($args);instead of retrieving all appointments.
core/bookings/api-booking.php- Old: permission callbacks returned
truefor REST routes. - New: routes use
[$this, 'get_item_permission_callback']and[$this, 'update_item_permission_callback']. - Introduces methods that extract
X-WP-Noncefrom request headers and validate withwp_verify_nonce($nonce, 'wp_rest').
- Old: permission callbacks returned
-
How do these changes fix the vulnerability?
- The appointment query now restricts returned records for users lacking
manage_options, preventing global listing of all appointments. - The REST endpoints now require a valid WordPress REST nonce. This prevents anonymous access and mitigates CSRF by ensuring the request originates from a valid authenticated session.
- The appointment query now restricts returned records for users lacking
-
Security improvements introduced
- Authorization is enforced at the REST route level.
- Data access is limited based on user capability for front-end listing.
- The plugin behavior aligns with WordPress REST API best practices: do not allow unconditionally authorized routes.
4. Proof of Concept (PoC) Guide
-
Prerequisites
- WordPress site with WP Timetics plugin version <= 1.0.36 installed and active.
- Access to the site from an attacker-controlled machine.
- Knowledge of the plugin’s REST endpoint paths or ability to enumerate through
/wp-json.
-
Step-by-step exploitation
- Discover the REST endpoint path for bookings, such as:
/wp-json/wp-timetics/v1/bookings- Or similar path used by the plugin.
- Send an unauthenticated GET request to the booking list endpoint:
curl -i https://target.example.com/wp-json/wp-timetics/v1/bookings
- If the endpoint is vulnerable, it will return HTTP 200 and booking data.
- To verify modification is possible, send an unauthenticated PATCH/PUT request to a booking item endpoint.
curl -X PATCH https://target.example.com/wp-json/wp-timetics/v1/bookings/123 -d '{"status":"cancelled"}'
- Observe the response. A vulnerable implementation will accept and apply the change.
- Discover the REST endpoint path for bookings, such as:
-
Expected behavior vs exploited behavior
- Expected behavior after patch:
- Unauthenticated requests should receive HTTP 401/403.
- Non-admin users should only see enabled/visible appointments.
- Exploited behavior in vulnerable versions:
- Unauthenticated users can retrieve full appointment lists.
- Booking records can be modified without valid credentials.
- Expected behavior after patch:
-
How to verify the vulnerability exists
- Inspect route registration for
permission_callback => function () { return true; }. - Execute REST requests without authentication and confirm access.
- For the meeting list, verify the query results include appointments with visibility other than
enabledwhen accessed by a non-admin or unauthenticated user.
- Inspect route registration for
5. Recommendations
-
Mitigation strategies
- Immediately upgrade WP Timetics to a patched version above 1.0.36.
- If patching is not immediately possible, disable the plugin until a secure version is available.
- Apply web application firewall rules to block suspicious REST API access patterns if possible.
-
Detection methods
- Audit plugin code for REST routes with
permission_callback => true. - Search for
wp_verify_nonceusage in permission callbacks and confirm it is present. - Monitor logs for unauthenticated access to
/wp-json/*endpoints and suspicious POST/PATCH activity. - Use vulnerability scanners to detect outdated plugin versions.
- Audit plugin code for REST routes with
-
Best practices to prevent similar issues
- Never return
truefrom a WordPress RESTpermission_callback. - Use
current_user_can()or WordPress nonce validation to enforce authorization. - Apply access controls at both the REST layer and data query layer.
- Separate read and write permissions and enforce least privilege.
- Review code for all public-facing API routes and ensure they validate authentication and authorization before processing requests.
- Never return