Jul 30, 2026·6 min read·25 visits
An authenticated low-privileged user (Provider or Secretary) in Easy!Appointments v1.5.2 can query the customer search endpoint to leak sensitive appointment hashes of other users, allowing subsequent unauthorized cancellation, rescheduling, or takeover of any appointment.
An Excessive Data Exposure vulnerability in Easy!Appointments v1.5.2 allows low-privileged administrative users, such as restricted Providers and Secretaries, to harvest unique, stateless appointment hashes belonging to other providers. These hashes act as capability tokens, granting full authorization to reschedule, take over, or delete appointments via stateless endpoints, resulting in a complete Broken Object Level Authorization (BOLA) scenario.
Easy!Appointments is a widely used open-source, self-hosted appointment scheduler. The application is built using the CodeIgniter PHP framework. To enable seamless, stateless booking management for end customers without requiring formal account creation, the software relies on unique, cryptographically random appointment hashes. These hashes are sent via email and serve as single-factor authorization tokens (capability URLs) for rescheduling or cancelling reservations.
The vulnerability, identified as CVE-2026-55651, is located within the administrative search endpoint /customers/search. This endpoint exposes sensitive database properties—specifically nested appointment data containing these secret appointment hashes—to authenticated dashboard users. The exposed metadata is not restricted based on the requesting user's operational role or scope of authority.
Because the administrative dashboard has multiple tiers of access control (including Administrators, Secretaries, and restricted Providers), this over-exposure allows low-privileged actors to bypass logical isolation barriers. A restricted provider or secretary can harvest secret hashes belonging to appointments managed by entirely different providers, laying the groundwork for unauthorized downstream modifications.
The root cause of CVE-2026-55651 is a combination of CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor) and CWE-639 (Authorization Bypass Through User-Controlled Key). The backend administrative search implementation failed to enforce tenant or ownership isolation rules before returning object trees.
When a dashboard user queries /customers/search, the application triggers the search() method inside application/controllers/Customers.php. The controller retrieves matching customer records and subsequently queries the Appointments_Model to resolve all historic and future appointments associated with each customer ID. The system does not verify whether the active session user has permission to manage those specific appointments.
Because the backend database maps multiple providers to shared customers, a restricted provider executing a customer lookup receives a complete record. This record contains the target customer's entire booking history, including the corresponding hash columns of records associated with peer providers. This architectural decision improperly treats the secret hash as generic, non-sensitive metadata within the internal representation, even though the state-changing endpoints rely on its secrecy.
The original implementation of the search() method in application/controllers/Customers.php blindly appended all returned appointments directly to the customer payload. Below is a comparative look at the vulnerable pattern and the server-side filtering implemented in the patch.
// VULNERABLE CODE PATH
$appointments = $this->appointments_model->get(['id_users_customer' => $customer['id']]);
// All appointments, including those of other providers, are left in $appointments
foreach ($appointments as &$appointment) {
$this->appointments_model->load($appointment, ['service', 'provider']);
}
$customer['appointments'] = $appointments;The security patch applied in Commit ebbe41130dafa58b0716426c56c8cfd4c22dbceb intercepts this collection. It dynamically checks the user's role slug and filters the collection in memory:
$user_id = session('user_id');
+ $role_slug = session('role_slug');
+
+ $secretary_provider_ids = [];
+
+ if ($role_slug === DB_SLUG_SECRETARY) {
+ $secretary_provider_ids = $this->secretaries_model->find($user_id)['providers'];
+ }
foreach ($customers as $index => &$customer) {
if (!$this->permissions->has_customer_access($user_id, $customer['id'])) {
@@ -211,6 +218,24 @@ public function search(): void
$appointments = $this->appointments_model->get(['id_users_customer' => $customer['id']]);
+ // If the current user is a provider, only include their own appointments.
+ if ($role_slug === DB_SLUG_PROVIDER) {
+ $appointments = array_filter($appointments, function ($appointment) use ($user_id) {
+ return (int) $appointment['id_users_provider'] === (int) $user_id;
+ });
+ $appointments = array_values($appointments);
+ }
+
+ // If the current user is a secretary, only include appointments of their providers.
+ if ($role_slug === DB_SLUG_SECRETARY) {
+ $appointments = array_filter($appointments, function ($appointment) use ($secretary_provider_ids) {
+ return in_array((int) $appointment['id_users_provider'], $secretary_provider_ids);
+ });
+ $appointments = array_values($appointments);
+ }While this fix prevents information exposure through this specific controller, it is an in-memory filter implemented after retrieving the entire dataset from the database. A highly optimal pattern would incorporate these role-based constraints directly into the SQL query execution layer to reduce database and memory resource allocation.
An attacker with valid administrative dashboard credentials (such as a restricted Provider) can exploit this flaw using basic HTTP interception tools. The attack sequence consists of two stages: information harvesting and stateless parameter execution.
First, the attacker logs into the dashboard and generates an API request using the browser's developer console or an external tool like Burp Suite. By sending a request such as GET /index.php/customers/search?keyword=John, the attacker retrieves a JSON structure containing customer profiles. Within this payload, the attacker targets the nested appointments array to retrieve the hash value for a booking overseen by a different provider.
Second, the attacker leverages the stateless behavior of the modification endpoints. By passing the captured hash directly to POST /index.php/calendar/delete_appointment or by navigating to /index.php/calendar/reschedule/{hash}, the attacker can alter or cancel the appointment. Because the application trusts the presence of the secret hash as absolute proof of authority, it completes the requested action without verifying if the attacker's active session is authorized to modify that specific provider's schedule.
The impact of successful exploitation is high because it allows malicious actors to systematically sabotage scheduling operations. By using automated search scripts, an attacker can harvest all active booking hashes and programmatically delete or reschedule every appointment in the system.
This flaw represents a logical Denial of Service (DoS) against business operations. It does not crash the database or web server, but it invalidates the integrity of the scheduling data. Additionally, it leaks the names, email addresses, phone numbers, and notes of patients or clients, violating confidentiality standards.
The CVSS v3.1 score is calculated as 7.1 (High) with vector string CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N. The integrity impact is rated high because any booking can be altered, while the confidentiality impact is rated low because overall database access remains restricted to scheduling metadata.
The primary remediation for this vulnerability is upgrading the Easy!Appointments installation to version 1.6.0 or later. This release enforces server-side filtering on search queries, preventing the disclosure of appointment metadata to unauthorized users.
For administrators who cannot immediately perform an upgrade, a manual backport of the PHP changes shown in the patch analysis section is recommended. This modification must be carefully applied to the search method in application/controllers/Customers.php.
As a defense-in-depth practice, administrators should implement strict access control rules on stateless modification endpoints. For example, the application should be configured to verify that the creator of an appointment modification request is the owner of the appointment record, rather than relying solely on the secret hash.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
easyappointments alextselegidis | = 1.5.2 | 1.6.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-200 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 7.1 (High) |
| EPSS Score | 0.00185 (0.185% probability) |
| Exploit Status | poc |
| CISA KEV Status | Not Listed |
The product exposes sensitive information to an actor who is not explicitly authorized to have access to that information.
CVE-2026-107725 is a critical security bypass in Hazelcast where missing authorization checks in the MapPermission class permit unprivileged clients to issue queries containing aggregators or projections. This architectural oversight allows attackers to run arbitrary code on the cluster servers under the privileges of the active Hazelcast process.
A stored Cross-Site Scripting (XSS) vulnerability was identified in Indico, an open-source event management system developed at CERN, prior to version 3.3.13. The vulnerability stems from weak URL validation in custom link fields and lack of HTML sanitization during Marshmallow serialization of event notes. This allows authenticated attackers with event modification privileges to inject malicious payloads that execute in the browser of users viewing the event pages or collaborating on notes.
A technical analysis of CVE-2026-107397, a stored Cross-Site Scripting (XSS) vulnerability in Indico's collaborative notes editor and custom link generation fields. Prior to version 3.3.13, Marshmallow serialization schemas omitted HTML sanitization during conflict resolution, and form validators failed to enforce strict URI schemes, enabling authenticated low-privilege attackers to execute arbitrary JavaScript.
An authorization bypass vulnerability exists in the legacy session export API of Indico, an open-source event management system developed at CERN. Due to a missing object-level access check, authenticated users can bypass configuration-level restrictions to extract private session metadata (including session titles, descriptions, and list of conveners) from events that they are otherwise authorized to view.
An incomplete Server-Side Request Forgery (SSRF) validation check in Indico prior to version 3.3.13 allows authenticated event organizers to bypass outbound network restrictions. By utilizing backslash characters within crafted URLs, attackers can exploit a parser differential between the application's validator and the downstream HTTP client library to access internal network resources.
CVE-2026-107717 represents a critical prompt boundary bypass and chat role injection vulnerability in the Banks Python package (versions prior to 2.5.0). The library parses generated template outputs line-by-line, attempting to validate each segment as a JSON-serialized ChatMessage object without validating the source boundaries of the text. If an application integrates user input directly into a prompt template, a remote, unauthenticated attacker can supply multi-line inputs with structured JSON payloads. This input is then parsed as high-privilege system instructions or tool execution responses, completely hijacking downstream Large Language Model behavior.