GHSA-996f-334j-67g7: Easy!Appointments disable_booking_message rendered as raw HTML on public booking page — Stored XSS
Summary
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.
Root Cause — Step by Step Code Flow
Step 1 — Rich text editor value stored without sanitization
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'),
});
Step 2 — Settings controller saves value verbatim
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);
Step 3 — Public booking controller forwards stored value to view
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,
]);
Step 4 — Public view renders value without escaping
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.
Proof of Concept
Step 1 — Store malicious disabled-booking message as admin:
POST /index.php/booking_settings/save HTTP/1.1
Host: 1
Details
Original advisory: https://github.com/advisories/GHSA-996f-334j-67g7
Exploitation outlook
EPSS (FIRST.org) estimates each CVE’s probability of exploitation in the next 30 days — here is the CSIRTS.com read on those numbers.
- Low exploitation riskCVE-2026-528380.18% 30-day exploitation probability — currently an unlikely target, but scores change as exploit code circulates. Riskier than 8% of all scored CVEs.
Referenced CVEs
| CVE | CSIRTS overview | External |
|---|---|---|
| CVE-2026-52838 | coverage & exploitation status | NVD · CVE.org |
Same CVEs, other sources
How other CERTs, PSIRTs and databases cover the vulnerabilities in this advisory.
More from GitHub Security Advisories
- mediumGHSA-jr6p-8pjj-mfx6: Capsule has an incomplete fix of CVE-2026-22872: TenantResource RawItems and Generators s…2026-07-31
- mediumGHSA-68cj-mvg9-rgm2: Capsule: CapsuleConfiguration NodeMetadata regex fields lack webhook validation, allowing…2026-07-31
- mediumGHSA-ff84-5f28-78qj: re2: Out-of-bounds heap read in `exec`/`test`/`match` via attacker-influenced `lastIndex`…2026-07-31
- mediumGHSA-6hxr-mr5r-9836: re2: Global `String.prototype.match` with an empty-matchable pattern never advances → inf…2026-07-31
- mediumGHSA-x83g-979r-f5fh: Sylius Mollie Plugin has unauthenticated IDOR that leaks order token and customer PII2026-07-31