CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-52840

CVE-2026-52840: Server-Side Request Forgery in Easy!Appointments CalDAV Connector

Amit Schendel
Amit Schendel
Senior Security Researcher

Jul 30, 2026·6 min read·4 visits

Executive Summary (TL;DR)

An authenticated SSRF vulnerability in Easy!Appointments prior to 1.6.0 allows backend users to probe internal networks and access loopback and RFC1918 addresses via unvalidated CalDAV connection test requests.

Easy!Appointments prior to version 1.6.0 is vulnerable to Server-Side Request Forgery (SSRF) within its CalDAV integration module. The system handles user-supplied URLs in the connection test endpoint without verifying host constraints or network schemes, allowing authenticated backend users to probe internal infrastructure.

Vulnerability Overview

Easy!Appointments is an open-source, self-hosted appointment scheduling platform implemented in PHP. The platform provides synchronization capabilities with external calendars using the CalDAV protocol. This functionality is exposed via the controller located at application/controllers/Caldav.php and managed through the Caldav_sync library.

In versions prior to 1.6.0, the application exposes a CalDAV connection verification endpoint designed to test connection parameters to remote CalDAV servers. This feature does not enforce restrictions on the host, protocol, or IP range of the destination URL. Consequently, an authenticated backend user (such as an administrator, provider, or secretary) can manipulate the configuration to initiate outbound connections targeting restricted systems.

Because the backend uses the Guzzle HTTP client to execute these network requests, and handles execution failures by echoing exception details, the vulnerability manifests as a semi-blind Server-Side Request Forgery (SSRF). Attackers can abuse this vector to scan local ports, map internal networks, or query cloud metadata services.

Root Cause Analysis

The root cause of this vulnerability lies in the missing network validation within the Caldav::connect_to_server method and its downstream implementation in Caldav_sync::get_http_client. When a user initiates a CalDAV connection test, the backend accepts a user-provided parameter called caldav_url.

The application validates this input using only PHP's native validation filter: filter_var($caldav_url, FILTER_VALIDATE_URL). This check is insufficient for security enforcement. The filter only verifies that the input complies with RFC 2396 syntax for URLs; it does not validate the protocol scheme, target hostname, or destination IP addresses.

When Guzzle executes the subsequent custom HTTP REPORT request, it attempts to resolve the provided address. If the target resides on the loopback interface (127.0.0.1), an internal private subnet (RFC 1918), or a link-local network (169.254.169.254), the server initiates the network connection. If the target server responds with an error or rejects the request, Guzzle throws an exception. The application catches this exception and returns up to 120 bytes of the response body and the HTTP status code inside the JSON payload, providing a highly descriptive information oracle to the caller.

Source Code & Patch Analysis

A detailed review of the patches reveals a multi-stage remediation approach. The core security control relies on resolving hostnames before executing requests and validating the resulting IP addresses against reserved ranges.

In the original vulnerable code, the get_http_client function was defined as follows:

private function get_http_client(string $caldav_url, string $caldav_username, string $caldav_password): Client
{
    if (!filter_var($caldav_url, FILTER_VALIDATE_URL)) {
        throw new InvalidArgumentException('Invalid CalDAV URL provided: ' . $caldav_url);
    }
    // Outbound HTTP client initialization and request execution follow
}

The initial security patch in commit 4abb10545d83ac1a57d03f6502376ee67696ea7c replaced this permissive validation with the assert_safe_caldav_url() method. This helper parses the URL scheme and checks whether the resolved IP addresses fall within private or reserved networks:

private function assert_safe_caldav_url(string $caldav_url): void
{
    if (!filter_var($caldav_url, FILTER_VALIDATE_URL)) {
        throw new InvalidArgumentException('Invalid CalDAV URL provided.');
    }
 
    $scheme = strtolower((string) parse_url($caldav_url, PHP_URL_SCHEME));
    $host = trim((string) parse_url($caldav_url, PHP_URL_HOST), '[]');
 
    if (!in_array($scheme, ['http', 'https'], true) || empty($host)) {
        throw new InvalidArgumentException('Invalid CalDAV URL provided.');
    }
 
    $resolved_ips = $this->resolve_host_ips($host);
    if (empty($resolved_ips)) {
        throw new InvalidArgumentException('CalDAV URL host cannot be resolved.');
    }
 
    foreach ($resolved_ips as $resolved_ip) {
        if (!filter_var($resolved_ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
            throw new InvalidArgumentException('CalDAV URL host is not allowed.');
        }
    }
}

Additionally, the exception handler was refactored in application/controllers/Caldav.php to suppress raw exception output. Instead of echoing $e->getMessage(), which exposed remote banners, the endpoint now maps errors to static localization strings such as calendar_sync_failed or invalid_credentials_provided.

Exploitation Mechanics

To exploit this vulnerability, an attacker must first obtain credentials for a backend account with roles such as administrator, provider, or secretary. Once authenticated, the attacker accesses the connection verification feature.

The attacker constructs an HTTP POST request targeting /index.php/caldav/connect_to_server containing a loopback or RFC 1918 address inside the caldav_url parameter:

POST /index.php/caldav/connect_to_server HTTP/1.1
Host: target-scheduler.local
Content-Type: application/x-www-form-urlencoded
Cookie: csrf_cookie_name=...; easyappointments_session=...
 
caldav_url=http://127.0.0.1:8025/&caldav_username=test&caldav_password=test

If the targeted port is closed, the Guzzle client throws a connection error, which is caught and returned to the attacker's browser as a failed connection message:

{
  "success": false,
  "message": "cURL error 7: Failed to connect to 127.0.0.1 port 8025: Connection refused..."
}

If the targeted port is open, the outbound Guzzle client receives response headers or an error page from the target internal service. Because Guzzle throws a RequestException for unexpected HTTP statuses (like 404 or 405), the controller catches this exception and returns up to 120 bytes of the response body. This lets the attacker fingerprint the software running on the internal asset:

{
  "success": false,
  "message": "Client error: REPORT http://127.0.0.1:8025 resulted in a 405 Method Not Allowed response: <!DOCTYPE html><html lang=\"en\"><head><title>Mailpit</title>..."
}

Bypass Scenarios & Security Logic Assessment

While the validation routine in 1.6.0 addresses direct requests to internal IP addresses, several advanced exploitation vectors require consideration.

First, Guzzle follows HTTP redirects by default. If the application validates an initial host pointing to a public IP address (e.g., http://malicious-public-domain.com), the check succeeds. However, if that public server responds with an HTTP 302 redirect pointing to an internal loopback URL, Guzzle may follow it internally without re-validating the redirected destination, bypassing pre-flight host validation.

Second, DNS Rebinding poses a risk because of Time-of-Check to Time-of-Use (TOCTOU) discrepancies. During the initial validation, the server resolves the target hostname using PHP's resolver, which returns a benign public IP. When Guzzle subsequently executes the request, it resolves the hostname a second time. If the domain's DNS record is configured with a TTL of 0, the second lookup can resolve to a private IP (e.g., 127.0.0.1), bypassing the validation phase.

Finally, commit 2da2baed18ec32ad7916e507815709c8f010d510 introduced a hardcoded exception for local Docker setups: if ($scheme === 'http' && strtolower($host) === 'baikal') { return; }. While intended for developer utility, any inconsistency between the hostname parsing of PHP's parse_url and Guzzle's PSR-7 parser could potentially be leveraged to bypass host restrictions.

Remediation & Detection Engineering

Remediation of CVE-2026-52840 requires upgrading to Easy!Appointments version 1.6.0 or later. The update implements hostname resolution checks, maps Guzzle exception outputs to static error messages, and removes options that allow user-controlled parameters to toggle SSRF safety checks.

For instances where upgrading is not immediately possible, security teams should implement local outbound network constraints. Egress filtering rules at the host or container firewall level (e.g., iptables, Docker network routing) must be applied to block the scheduling application from establishing TCP connections to loopback interfaces and RFC 1918 networks.

Detection can be achieved by monitoring proxy and application logs for unusual hostnames in the CalDAV connection requests. Network intrusion detection systems can also identify outbound HTTP REPORT requests originating from the application server that target local or private IP addresses.

Official Patches

alextselegidisOfficial patch integration commit on GitHub

Fix Analysis (4)

Technical Appendix

CVSS Score
2.7/ 10
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:N/A:N
EPSS Probability
0.19%
Top 92% most exploited

Affected Systems

Easy!Appointments scheduling platform

Affected Versions Detail

Product
Affected Versions
Fixed Version
easyappointments
alextselegidis
< 1.6.01.6.0
AttributeDetail
CWE IDCWE-918
Attack VectorNetwork
CVSS v3.1 Score2.7
EPSS Score0.00186 (Percentile: 8.49%)
Exploit Statuspoc
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1005Data from Local System
Collection
CWE-918
Server-Side Request Forgery (SSRF)

The web server receives a physical address or URL from an upstream user and does not validate the host domain or target IP address, allowing unauthorized requests to restricted targets.

Vulnerability Timeline

Vulnerability published via GHSA-pm5p-7w5h-jm5q and CVE-2026-52840
2026-07-14
Advisory details and patch structure updated
2026-07-17

References & Sources

  • [1]GHSA-pm5p-7w5h-jm5q Advisory Details
  • [2]NVD - CVE-2026-52840 Detail
  • [3]CVE.org CVE-2026-52840 Record

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 1 hour ago•CVE-2026-55651
7.1

CVE-2026-55651: Excessive Data Exposure and BOLA in Easy!Appointments Customer Search

An Excessive Data Exposure vulnerability in Easy!Appointments v1.5.2 allows low-privileged administrative users, such as restricted Providers and Secretaries, to harvest unique, stateless appointment hashes belonging to other providers. These hashes act as capability tokens, granting full authorization to reschedule, take over, or delete appointments via stateless endpoints, resulting in a complete Broken Object Level Authorization (BOLA) scenario.

Amit Schendel
Amit Schendel
2 views•6 min read
•about 3 hours ago•CVE-2026-52839
3.3

CVE-2026-52839: Cross-Provider Appointment Injection and Authorization Bypass in Easy!Appointments

An authorization bypass and logical 'write-before-crash' vulnerability in Easy!Appointments versions prior to 1.6.0 allows authenticated users with the 'Provider' role to inject unauthorized bookings into foreign providers' schedules or reassign existing appointments via parameter manipulation on the 'store' and 'update' endpoints.

Alon Barad
Alon Barad
5 views•6 min read
•about 4 hours ago•CVE-2026-52837
6.9

CVE-2026-52837: Unauthenticated PII Leakage in Easy!Appointments Booking Reschedule Endpoint

An unauthenticated Personally Identifiable Information (PII) disclosure vulnerability exists in Easy!Appointments versions up to and including 1.5.2. Requesting the booking reschedule endpoint with a valid appointment hash causes the system to embed the raw customer database record into the HTML response as inline JavaScript variables, exposing sensitive details. This includes email addresses, phone numbers, physical addresses, custom database metadata, and internal directory configurations such as LDAP DNs. The vulnerability has been resolved in version 1.6.0.

Amit Schendel
Amit Schendel
4 views•12 min read
•about 5 hours ago•CVE-2026-52841
3.1

CVE-2026-52841: Authorization Bypass in Easy!Appointments Google OAuth Provider Binding

An authorization bypass vulnerability exists in Easy!Appointments before version 1.6.0. The application fails to validate ownership of the provider ID during the Google OAuth synchronization process. This allows authenticated backend users to link their personal Google Calendars to peer providers, leading to unauthorized access to scheduled appointments and associated customer metadata.

Amit Schendel
Amit Schendel
5 views•6 min read
•about 6 hours ago•CVE-2026-52838
2.6

CVE-2026-52838: Stored Cross-Site Scripting via Booking Disabled Message in Easy!Appointments

This report provides a comprehensive technical teardown of CVE-2026-52838 (GHSA-996f-334j-67g7), a stored Cross-Site Scripting (XSS) vulnerability in Easy!Appointments. The flaw occurs in how the application manages the 'booking disabled' custom message configuration, allowing high-privileged administrators to persist unsanitized payloads that execute on unauthenticated guest landing pages.

Alon Barad
Alon Barad
5 views•6 min read
•about 7 hours ago•CVE-2026-54574
8.2

CVE-2026-54574: Symlink Escape and Arbitrary Host File Write in proot-distro

CVE-2026-54574 (GHSA-9xq3-3fqg-4vg7) is a critical Symlink Escape and Arbitrary Host File Write vulnerability in proot-distro, an open-source utility for managing rootless PRoot containers on Termux and general Linux environments. The vulnerability is rooted in an asymmetric validation flaw during the archive extraction process of container installations, Docker/OCI layers, and container backup restorations. While the extraction engine successfully validated file names to prevent standard directory traversal (e.g., rejecting components containing '..'), it failed to validate symbolic link targets. An attacker could craft a malicious tar archive or container image that plants an absolute host-path symlink. Subsequent file members within the same archive could then traverse through this symlink, writing arbitrary files directly onto the host filesystem under the privileges of the executing process.

Amit Schendel
Amit Schendel
7 views•5 min read