Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-52840

CVE-2026-52840: Easy!Appointments SSRF Vulnerability

CVE-2026-52840 is an SSRF flaw in Easy!Appointments allowing authenticated users to reach internal network hosts. This post covers the technical details, affected versions, security impact, and mitigation steps.

Published:

CVE-2026-52840 Overview

CVE-2026-52840 is a Server-Side Request Forgery (SSRF) vulnerability in Easy!Appointments, a self-hosted appointment scheduler. The flaw resides in the Caldav::connect_to_server method at application/controllers/Caldav.php:60, which forwards a user-supplied caldav_url to a Guzzle REPORT request without validating the scheme or host. Authenticated backend users (admin, provider, or secretary) can direct requests to loopback, RFC1918, and link-local addresses on the deployment's network. Versions prior to 1.6.0 are affected, and version 1.6.0 contains the patch.

Critical Impact

Authenticated backend users can reach internal network endpoints and extract limited response data through Guzzle exception messages, enabling semi-blind SSRF against internal services.

Affected Products

  • Easy!Appointments versions prior to 1.6.0
  • application/controllers/Caldav.php component
  • application/libraries/Caldav_sync.php library

Discovery Timeline

  • 2026-07-14 - CVE-2026-52840 published to NVD
  • 2026-07-15 - Last updated in NVD database

Technical Details for CVE-2026-52840

Vulnerability Analysis

The vulnerability is classified as Server-Side Request Forgery [CWE-918]. The Caldav::connect_to_server method accepts a caldav_url parameter from the request and passes it directly to a Guzzle HTTP client REPORT call. No validation is performed on the URL scheme or destination host before the outbound request is issued.

The semi-blind nature of the SSRF stems from the exception handling path at Caldav.php:74-78. When Guzzle raises an exception, the controller returns the upstream HTTP status code and approximately 120 bytes of the response body inside the JSON message field. Attackers can use this leaked data to fingerprint internal services and enumerate reachable hosts.

Exploitation requires authenticated access as an admin, provider, or secretary role. The attacker sends a crafted CalDAV connection request pointing at an internal target such as http://127.0.0.1/, http://169.254.169.254/, or an RFC1918 address on the server's network.

Root Cause

The controller lacks scheme and host validation before invoking Guzzle. The upstream library Caldav_sync supports an enable_ssrf_check toggle, but the controller previously exposed this via a configuration constant that could be disabled, and the host filtering logic was not consistently enforced at the request boundary.

Attack Vector

The attack vector is network-based and requires backend authentication. An attacker with valid credentials submits a CalDAV configuration containing a caldav_url pointing to an internal address, then reads the returned status code and truncated response body from the JSON error message.

php
// Patch: application/controllers/Caldav.php
     {
         parent::__construct();
 
-        $this->load->library('caldav_sync', [
-            'enable_ssrf_check' => defined('Config::ENABLE_CALDAV_SSRF_CHECK')
-                ? (bool) Config::ENABLE_CALDAV_SSRF_CHECK
-                : true,
-        ]);
+        $this->load->library('caldav_sync');
 
         $this->load->model('appointments_model');
         $this->load->model('unavailabilities_model');

Source: GitHub Commit 6eb9336

php
// Patch: application/libraries/Caldav_sync.php
 class Caldav_sync
 {
+    // Toggle SSRF host validation here (enabled by default).
     protected bool $enable_ssrf_check = true;

Source: GitHub Commit 6eb9336

The fix removes the externally toggleable SSRF check and keeps validation enforced inside the Caldav_sync library by default.

Detection Methods for CVE-2026-52840

Indicators of Compromise

  • Outbound HTTP requests from the Easy!Appointments application server directed at loopback (127.0.0.0/8), RFC1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), or link-local (169.254.0.0/16) addresses.
  • CalDAV configuration requests containing internal IP literals or non-https/http schemes in the caldav_url parameter.
  • Application error logs showing repeated Guzzle exceptions from the Caldav::connect_to_server handler with varying target hosts.

Detection Strategies

  • Inspect web server access logs for authenticated POST requests to CalDAV connection endpoints where the payload references private address ranges.
  • Correlate backend user sessions with outbound network flows from the application host to unexpected internal destinations.
  • Alert on JSON response bodies from the CalDAV endpoint containing HTTP status codes that would only originate from internal services.

Monitoring Recommendations

  • Enable egress network monitoring on the Easy!Appointments host to flag connections to internal-only address ranges.
  • Audit backend account activity for provider, secretary, and admin roles performing CalDAV configuration changes.
  • Retain application-layer logs capturing the caldav_url parameter for post-incident analysis.

How to Mitigate CVE-2026-52840

Immediate Actions Required

  • Upgrade Easy!Appointments to version 1.6.0 or later, which enforces SSRF host validation inside the Caldav_sync library by default.
  • Review and revoke unnecessary backend accounts holding admin, provider, or secretary roles.
  • Rotate credentials for any backend user that may have been abused prior to patching.

Patch Information

The fix is delivered in Easy!Appointments 1.6.0. Refer to the GitHub Security Advisory GHSA-pm5p-7w5h-jm5q and the GitHub Commit 6eb9336 for the reference implementation.

Workarounds

  • Restrict egress traffic from the Easy!Appointments host using host-based or network firewalls to block access to loopback, RFC1918, and link-local ranges.
  • Place the application behind an outbound proxy that enforces an allowlist of external CalDAV providers.
  • Limit backend role assignments to trusted personnel until the upgrade is applied.
bash
# Example: block outbound access to internal ranges from the app host (iptables)
iptables -A OUTPUT -m owner --uid-owner www-data -d 127.0.0.0/8 -j REJECT
iptables -A OUTPUT -m owner --uid-owner www-data -d 10.0.0.0/8 -j REJECT
iptables -A OUTPUT -m owner --uid-owner www-data -d 172.16.0.0/12 -j REJECT
iptables -A OUTPUT -m owner --uid-owner www-data -d 192.168.0.0/16 -j REJECT
iptables -A OUTPUT -m owner --uid-owner www-data -d 169.254.0.0/16 -j REJECT

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.