CVE-2026-2262

Easy Appointments <= 3.12.21 - Unauthenticated Sensitive Information Exposure via REST API

highExposure of Sensitive Information to an Unauthorized Actor
7.5
CVSS Score
7.5
CVSS Score
high
Severity
3.12.22
Patched in
1d
Time to patch

Description

The Easy Appointments plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 3.12.21 via the `/wp-json/wp/v2/eablocks/ea_appointments/` REST API endpoint. This is due to the endpoint being registered with `'permission_callback' => '__return_true'`, which allows access without any authentication or authorization checks. This makes it possible for unauthenticated attackers to extract sensitive customer appointment data including full names, email addresses, phone numbers, IP addresses, appointment descriptions, and pricing information.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.12.21
PublishedApril 17, 2026
Last updatedApril 17, 2026
Affected plugineasy-appointments

What Changed in the Fix

Changes introduced in v3.12.22

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Vulnerability Research Plan: CVE-2026-2262 - Easy Appointments Sensitive Information Exposure ## 1. Vulnerability Summary The **Easy Appointments** plugin for WordPress is vulnerable to **Sensitive Information Exposure** in versions up to and including 3.12.21. The vulnerability exists because th…

Show full research plan

Vulnerability Research Plan: CVE-2026-2262 - Easy Appointments Sensitive Information Exposure

1. Vulnerability Summary

The Easy Appointments plugin for WordPress is vulnerable to Sensitive Information Exposure in versions up to and including 3.12.21. The vulnerability exists because the plugin registers a REST API endpoint /wp-json/wp/v2/eablocks/ea_appointments/ with a 'permission_callback' set to '__return_true'. This allows any unauthenticated user to query the endpoint and retrieve the full contents of the ea_appointments and ea_fields database tables, which contain sensitive customer data such as full names, email addresses, phone numbers, and appointment descriptions.

2. Attack Vector Analysis

  • Endpoint: GET /wp-json/wp/v2/eablocks/ea_appointments/
  • Authentication: None Required (Unauthenticated).
  • Permissions: Open to all users via permission_callback => '__return_true'.
  • Parameters:
    • location (optional, integer)
    • service (optional, integer)
    • worker (optional, integer)
    • search (optional, string)
  • Preconditions: The plugin must be active. At least one appointment must exist in the database for the exposure to be demonstrable.

3. Code Flow

  1. Registration: In ea-blocks/ea-blocks.php, the rest_api_init action (lines 216-222) registers the route:
    register_rest_route('wp/v2/eablocks', '/ea_appointments/', [
        'methods'  => 'GET',
        'callback' => 'easy_ea_block_get_appointments',
        'permission_callback' => '__return_true',
    ]);
    
  2. Callback Execution: When the endpoint is hit, easy_ea_block_get_appointments is called (lines 119-146). It extracts parameters and calls easy_ea_block_get_all_appointments($data).
  3. Data Retrieval: easy_ea_block_get_all_appointments (lines 148-189) performs a SELECT * on the appointments table:
    $query = "SELECT * FROM $tableName WHERE 1 {$location}{$service}{$worker}{$status}{$search} ORDER BY id DESC";
    $apps = $wpdb->get_results($sql, OBJECT_K);
    
  4. Metadata Enrichment: It then calls easy_ea_block_get_fields_for_apps($ids) (lines 201-212), which joins the meta-fields and field values tables to retrieve specific customer details (Name, Email, Phone, etc.).
  5. Response: The combined data object is returned as a JSON response to the unauthenticated requester.

4. Nonce Acquisition Strategy

This vulnerability does not require a WordPress nonce. The REST API endpoint is registered with 'permission_callback' => '__return_true', and the method is GET. WordPress REST API nonces (_wpnonce) are primarily used for CSRF protection on state-changing requests (POST/PUT/DELETE) or when the permission_callback requires a logged-in session. For this specific "Sensitive Information Exposure" vulnerability, an unauthenticated GET request will succeed without any headers or tokens.

5. Exploitation Strategy

  1. Target URL: http://<target-ip>/wp-json/wp/v2/eablocks/ea_appointments/
  2. Method: GET
  3. Request tool: http_request
  4. Payload: None required. Optionally, append ?search= to verify filtering, but a bare request is sufficient.
  5. Headers: None required.

6. Test Data Setup

To prove the exploit, the environment must contain sensitive data. Use wp-cli to simulate a user booking:

  1. Create Location/Service/Worker:
    # These tables are created on plugin activation. Use wp db query to insert prerequisites.
    wp db query "INSERT INTO wp_ea_locations (name) VALUES ('Test Clinic');"
    wp db query "INSERT INTO wp_ea_services (name) VALUES ('General Checkup');"
    wp db query "INSERT INTO wp_ea_staff (name) VALUES ('Dr. Smith');"
    wp db query "INSERT INTO wp_ea_connections (location, service, worker, is_working) VALUES (1, 1, 1, 1);"
    
  2. Create Meta Fields:
    wp db query "INSERT INTO wp_ea_meta_fields (id, slug, label, type) VALUES (1, 'email', 'Email', 'text'), (2, 'phone', 'Phone', 'text'), (3, 'name', 'Name', 'text');"
    
  3. Create an Appointment with Sensitive Info:
    wp db query "INSERT INTO wp_ea_appointments (id, location, service, worker, date, start, end, status) VALUES (1337, 1, 1, 1, '2025-05-20', '10:00:00', '10:30:00', 'confirmed');"
    wp db query "INSERT INTO wp_ea_fields (app_id, field_id, value) VALUES (1337, 1, 'victim@example.com'), (1337, 2, '555-0199'), (1337, 3, 'John Doe');"
    

7. Expected Results

A successful exploit will return a 200 OK response with a JSON array. Each element in the array will represent an appointment and must contain:

  • id: The appointment ID (e.g., 1337).
  • name: "John Doe" (Retrieved via easy_ea_block_get_fields_for_apps).
  • email: "victim@example.com".
  • phone: "555-0199".
  • Internal fields like location, service, worker, date, start, end.

8. Verification Steps

  1. HTTP Check: Inspect the response from the http_request tool for the string "victim@example.com" and "John Doe".
  2. Database Correlation: Use wp-cli to verify the data exists in the database to ensure the response matches the "sensitive" source:
    wp db query "SELECT * FROM wp_ea_fields WHERE app_id = 1337"
    

9. Alternative Approaches

If the main endpoint /ea_appointments/ is partially restricted or fails, check the secondary endpoint registered in the same block:

  • Secondary Endpoint: GET /wp-json/wp/v2/eablocks/get_ea_options/
  • Analysis: This endpoint (lines 106-110, lines 225-270) is also registered with __return_true. While it primarily returns configuration options for locations, services, and staff, it may leak the internal structure and IDs of the booking system, facilitating more targeted queries to the main vulnerable endpoint.
  • Filter Bypass: If the plugin uses any custom WAF or security plugins, try adding a search parameter: /wp-json/wp/v2/eablocks/ea_appointments/?search=@ (to target emails).

Check if your site is affected.

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