Wappointment <=2.7.2 - Missing Authorization
Description
The Wappointment plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.7.6. 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:NTechnical Details
<=2.7.6What Changed in the Fix
Changes introduced in v2.7.7
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-68575 ## 1. Vulnerability Summary The **Wappointment** plugin (<= 2.7.6) is vulnerable to **Missing Authorization**. The vulnerability exists because an AJAX handler (likely associated with the `Wappointment\Models\Appointment\Recurrence` logic) fails to perfo…
Show full research plan
Exploitation Research Plan: CVE-2025-68575
1. Vulnerability Summary
The Wappointment plugin (<= 2.7.6) is vulnerable to Missing Authorization. The vulnerability exists because an AJAX handler (likely associated with the Wappointment\Models\Appointment\Recurrence logic) fails to perform a capability check (e.g., current_user_can( 'manage_options' )). This allows unauthenticated attackers to trigger the generation of recurring appointment instances for any master appointment ID, potentially leading to database exhaustion, schedule manipulation, or unauthorized creation of bookable slots.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
wappointment_generate_recurrence(inferred from theRecurrencemodel) orwappointment_sync_recurrence. - Authentication: None (Unauthenticated).
- HTTP Method: POST.
- Payload Parameters:
action:wappointment_generate_recurrence(inferred)appointment_id: The ID of a master recurring appointment.wappointment_nonce: A valid security nonce (if enforced).
3. Code Flow
- An unauthenticated user sends a POST request to
admin-ajax.phpwith a targetappointment_id. - The request is handled by a function registered via
wp_ajax_nopriv_wappointment_generate_recurrence. - The handler lacks a capability check. It fetches the appointment:
$master = Appointment::find($_POST['appointment_id']). - It instantiates the recurrence model:
$recurrence = new \Wappointment\Models\Appointment\Recurrence($master). - The constructor
__construct()initializes rules and boundaries based on the staff's calendar:$this->calendar = CalendarsBack::findById($this->master->staff_id). - The handler calls
$recurrence->generateChilds(). generateChilds()loops from the last generation date to the end of the availability window ($this->calendar['avb']).- For each valid day,
generateForDay()is called, which executesAppointment::create($data_new), inserting new rows into thewappo_appointmentstable.
4. Nonce Acquisition Strategy
The plugin likely enqueues a nonce for its booking and calendar functions.
- Identify Shortcode: The plugin typically uses the
[wappointment]shortcode to display the booking form. - Create Trigger Page:
wp post create --post_type=page --post_title="Booking" --post_status=publish --post_content='[wappointment]' - Navigate and Extract:
- Use
browser_navigateto visit the new page. - Use
browser_evalto extract the nonce from the localized script object: browser_eval("window.wappointment_data?.nonce")orbrowser_eval("window.wappo_data?.nonce").
- Use
5. Exploitation Strategy
Pre-condition
A master recurring appointment must exist. In a test environment, create one first.
Step 1: Trigger Recurrence Generation
Send an unauthenticated request to trigger the generation of future slots for a master appointment.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=wappointment_generate_recurrence&appointment_id=1&wappointment_nonce=[EXTRACTED_NONCE]
Step 2: Payload Analysis
If the specific action name wappointment_generate_recurrence fails, check app/System/Init.php (if available) or search the JS assets (dist/main.js) for strings matching wp_ajax to find the exact registration.
6. Test Data Setup
- Staff/Calendar: Create a staff member.
- Service: Create a service with recurring availability enabled.
- Master Appointment: Create an appointment with recurrence options:
# Example using WP-CLI to simulate a master appointment in the database wp db query "INSERT INTO wp_wappo_appointments (staff_id, client_id, start_at, end_at, options) VALUES (1, 1, '2025-01-01 10:00:00', '2025-01-01 11:00:00', '{\"recurrence\":{\"days\":[\"monday\",\"wednesday\"],\"last_gen\":\"2025-01-01 11:00:00\"}}')" - Note the ID: Capture the ID of the inserted row (usually
1).
7. Expected Results
- The server responds with a
200 OK(often returning JSON like{"success": true}). - The
wappo_appointmentstable will be populated with new entries representing future occurrences of the master appointment. - The
last_genvalue in the master appointment'soptionscolumn will be updated to the end of the availability window.
8. Verification Steps
- Check Database Count:
An increase in the count confirms the unauthorized generation.wp db query "SELECT COUNT(*) FROM wp_wappo_appointments WHERE parent = 1;" - Check Audit Trail: Verify the
last_genupdated:wp db query "SELECT options FROM wp_wappo_appointments WHERE id = 1;"
9. Alternative Approaches
If generateChilds is not directly exposed, the "Missing Authorization" might exist in:
- Client Update:
wappointment_update_clientaction. An attacker could change the email or options of an arbitraryclient_id(fromapp/Models/Client.php).- Body:
action=wappointment_update_client&id=[TARGET_ID]&email=attacker@example.com
- Body:
- Unauthorized Booking: If the validator
Wappointment\Validators\HttpRequest\Bookingis used in an endpoint that skips ownership checks, an attacker might book slots on behalf of other clients by specifying aclient_id.
Summary
The Wappointment plugin for WordPress (<= 2.7.6) is vulnerable to unauthorized access and modification of appointments due to predictable security tokens ('edit_key'). Unauthenticated attackers can guess these keys, which are generated using simple MD5 hashes of timestamps and IDs, allowing them to modify or cancel bookings without proper authorization.
Vulnerable Code
// app/Models/Appointment/Recurrence.php line 38 public function generateEditKey($start_at) { return md5($start_at); } --- // app/Models/Client.php line 36 public function generateEditKey($start_at) { return md5($this->id . $start_at); } --- // app/Validators/HttpRequest/Booking.php line 138 $result = apply_filters('wappointment_validate_booking', \true, $inputs, $this->service, $this->location, static::$startKey, $this->staff); if ($result !== \true) { throw new \WappointmentException("Error Processing Request", 1); }
Security Fix
@@ -38,7 +38,7 @@ } public function generateEditKey($start_at) { - return md5($start_at); + return bin2hex(random_bytes(16)); } private function generateForDay(Carbon $start_temp) { @@ -36,7 +36,7 @@ } public function generateEditKey($start_at) { - return md5($this->id . $start_at); + return bin2hex(random_bytes(16)); } public function getFirstName() { @@ -135,9 +135,11 @@ } $this->validateService($inputs); $this->validateLocation($inputs); - $result = apply_filters('wappointment_validate_booking', \true, $inputs, $this->service, $this->location, static::$startKey, $this->staff); - if ($result !== \true) { - throw new \WappointmentException("Error Processing Request", 1); + if (!isset($this->service->options['slots'])) { + $result = apply_filters('wappointment_validate_booking', \true, $inputs, $this->service, $this->location, static::$startKey, $this->staff); + if ($result !== \true) { + throw new \WappointmentException("Error Processing Request", 1); + } } $this->generateValidation($inputs);
Exploit Outline
The exploit leverages the predictability of the 'edit_key' tokens used to manage appointments without authentication. 1. An attacker identifies a target appointment's start timestamp and the associated client or staff ID, which are often available via the frontend booking calendar. 2. The attacker calculates the MD5 hash of these values (e.g., md5($timestamp) or md5($client_id . $timestamp)) to recreate the valid edit_key. 3. The attacker then submits an unauthenticated POST or GET request to the plugin's appointment management endpoints (such as cancellation or modification actions) using the guessed key. 4. Since the plugin relies on this predictable token rather than robust authorization checks, it grants the attacker full control over the targeted appointment record.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.