CVE-2026-11896

My Calendar <= 3.7.14 - Insecure Direct Object Reference to Unauthenticated Sensitive Information Disclosure via 'vcal' Parameter

mediumAuthorization Bypass Through User-Controlled Key
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
3.7.15
Patched in
1d
Time to patch

Description

The My Calendar – Accessible Event Manager plugin for WordPress is vulnerable to Insecure Direct Object Reference in all versions up to, and including, 3.7.14 via the 'vcal' parameter due to missing validation on a user controlled key. This makes it possible for unauthenticated attackers to enumerate occurrence IDs and access the full iCalendar export of non-public, draft, trashed, and personal calendar events, disclosing sensitive event metadata including titles, descriptions, dates, locations, organizer and host details, permalinks, and related calendar metadata.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Low
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=3.7.14
PublishedJuly 1, 2026
Last updatedJuly 2, 2026
Affected pluginmy-calendar

What Changed in the Fix

Changes introduced in v3.7.15

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-11896 (My Calendar IDOR) ## 1. Vulnerability Summary The **My Calendar** plugin for WordPress (versions <= 3.7.14) contains an Insecure Direct Object Reference (IDOR) vulnerability. The plugin exposes an iCalendar (.ics) export feature triggered by the `vcal` …

Show full research plan

Exploitation Research Plan: CVE-2026-11896 (My Calendar IDOR)

1. Vulnerability Summary

The My Calendar plugin for WordPress (versions <= 3.7.14) contains an Insecure Direct Object Reference (IDOR) vulnerability. The plugin exposes an iCalendar (.ics) export feature triggered by the vcal parameter. This feature fails to perform authorization checks on the event ID (occurrence ID) provided by the user. Consequently, unauthenticated attackers can access sensitive metadata for events that should be restricted, including Drafts, Trashed events, and Private events, by simply knowing or enumerating the ID.

2. Attack Vector Analysis

  • Endpoint: The main WordPress frontend (/ or index.php).
  • HTTP Parameter: vcal (GET parameter).
  • Value: An integer representing the occurrence_id of a calendar event.
  • Authentication: None (Unauthenticated).
  • Preconditions: The plugin must be active, and at least one non-public event (Draft, Private, or Trashed) must exist in the database.

3. Code Flow (Inferred)

Since the specific export handler file was not provided in the source dump but is referenced in the vulnerability description, the logic flow is as follows:

  1. Entry Point: The plugin likely hooks into init or wp_loaded to monitor for the vcal parameter.
  2. Handler: A function (likely my_calendar_vcal() or similar) identifies the presence of $_GET['vcal'].
  3. Data Retrieval: The code takes the integer from vcal and queries the wp_my_calendar (or wp_my_calendar_event) table to retrieve the event details.
  4. Vulnerability: The code proceeds to generate the ICS output headers (text/calendar) and event body without calling authorization checks like mc_event_is_hidden() or mc_event_published() (found in includes/conditionals.php).
  5. Sink: The event metadata is echoed to the output buffer, ending execution with exit; or die;.

4. Nonce Acquisition Strategy

According to the vulnerability description and standard behavior of iCal export links in this plugin, no nonce is required for the vcal parameter. These links are typically intended to be shareable/publicly accessible for calendar synchronization.

If a nonce were required, it would be found in the frontend script localization or a hidden field. To verify:

  1. Navigate to a public calendar page.
  2. Use browser_eval to search for mc_ prefixed variables:
    browser_eval("window.my_calendar_vars || window.mc_data")

However, for this specific CVE (IDOR to sensitive info), the exploit is expected to be a direct GET request.

5. Exploitation Strategy

The goal is to demonstrate that an unauthenticated request can retrieve an event that is NOT in a 'Public' state.

Step-by-Step Plan:

  1. Identify Occurrence ID: Use WP-CLI to find the ID of a "Draft" or "Private" event.
  2. Request Export: Send a GET request to the homepage with the vcal parameter set to that ID.
  3. Verify Content: Check if the response contains the BEGIN:VCALENDAR header and the private event's title/description.

Request Details:

  • URL: http://localhost:8080/index.php?vcal=[ID]
  • Method: GET
  • Headers: Accept: text/calendar (Optional, as the plugin forces the header).

6. Test Data Setup

The PoC requires events with different statuses to prove the bypass.

# 1. Create a Public event (to find the baseline ID range)
wp eval "mc_insert_event(array('event_title'=>'Public Event','event_desc'=>'Visible','event_begin'=>'2026-01-01','event_time'=>'12:00:00','event_end'=>'2026-01-01','event_endtime'=>'13:00:00','event_approved'=>1));"

# 2. Create a Draft event (event_approved = 0)
wp eval "mc_insert_event(array('event_title'=>'Secret Draft','event_desc'=>'Confidential Info','event_begin'=>'2026-02-01','event_time'=>'12:00:00','event_end'=>'2026-02-01','event_endtime'=>'13:00:00','event_approved'=>0));"

# 3. Create a Trashed event (event_approved = 2)
wp eval "mc_insert_event(array('event_title'=>'Trashed Event','event_desc'=>'Should be gone','event_begin'=>'2026-03-01','event_time'=>'12:00:00','event_end'=>'2026-03-01','event_endtime'=>'13:00:00','event_approved'=>2));"

# 4. Identify the occurrence IDs
# My Calendar stores occurrences in a separate table. We need the 'occur_id' from wp_my_calendar.
wp db query "SELECT occur_id, event_title, event_approved FROM wp_my_calendar INNER JOIN wp_my_calendar_events ON wp_my_calendar.occur_event_id = wp_my_calendar_events.event_id"

7. Expected Results

  • Unauthenticated Request: A request to ?vcal=[DRAFT_ID] should return an HTTP 200 response with Content-Type: text/calendar.
  • Information Disclosure: The body of the response should contain:
    • SUMMARY:Secret Draft
    • DESCRIPTION:Confidential Info
  • Baseline Comparison: A properly secured application would either return a 404, a 403, or a generic calendar file with no event data for a draft ID when requested by an unauthenticated user.

8. Verification Steps

  1. Check Response Headers: http_request should show Content-Type: text/calendar; charset=UTF-8.
  2. Verify Occurrence Mapping: Use WP-CLI to confirm the occur_id used in the request corresponds to the draft event:
    wp db query "SELECT event_approved FROM wp_my_calendar_events WHERE event_id = (SELECT occur_event_id FROM wp_my_calendar WHERE occur_id = [ID])"
  3. Confirm Lack of Authentication: Ensure the http_request was made without any Cookie headers representing a logged-in user.

9. Alternative Approaches

If the vcal parameter expects an event_id rather than an occur_id, or if the parameter is handled differently:

  • Try ?vcal=1 (standard IDOR enumeration).
  • Search the source for add_action( 'init' or add_action( 'wp_loaded' to find the exact function handling the vcal key.
  • If vcal is used in a redirect context (e.g., generating a file then redirecting), check if the file path is predictable in wp-content/uploads/. (Unlikely given the "sensitive information disclosure" via parameter description).
Research Findings
Static analysis — not yet PoC-verified

Summary

The My Calendar plugin for WordPress is vulnerable to an Insecure Direct Object Reference (IDOR) flaw in the iCalendar export functionality. Unauthenticated attackers can disclose sensitive event details—including those of draft, private, or trashed events—by supplying a specific occurrence ID to the 'vcal' parameter, as the plugin lacks authorization checks on the event's visibility status.

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/my-calendar/3.7.0/css/admin.css /home/deploy/wp-safety.org/data/plugin-versions/my-calendar/3.7.15/css/admin.css
--- /home/deploy/wp-safety.org/data/plugin-versions/my-calendar/3.7.0/css/admin.css	2026-01-20 22:57:52.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/my-calendar/3.7.15/css/admin.css	2026-06-14 19:35:06.000000000 +0000
@@ -218,6 +218,10 @@
 	color: var(--primary-dark);
 }
 
+.mc_edit_links {
+	clear: both;
+}
+
 .mc_edit_links ul {
 	display: flex;
 	gap: 10px;
@@ -553,6 +557,7 @@
 	font-style: italic;
 }
 
+.single-mc-event .mc-image,
 .mc-main .details .mc-image {
 	max-width: 100%;
 	height: auto;
... (truncated)

Exploit Outline

The exploit targets the iCalendar export feature triggered by the 'vcal' GET parameter. 1. Endpoint: The attacker targets the WordPress root (index.php) or any page where the My Calendar plugin is active. 2. Methodology: An unauthenticated attacker sends a GET request with the 'vcal' parameter set to an integer representing an event's occurrence ID (e.g., /?vcal=123). 3. Authentication: No authentication or specific nonces are required to access this endpoint. 4. Payload/Bypass: By enumerating occurrence IDs, the attacker can bypass visibility restrictions. The plugin fails to verify if the event status is 'Public' or if the user has permission to view the event, causing the server to return the full event metadata (including sensitive summaries and descriptions) in a 'text/calendar' (ICS) file format even for Drafts or Private events.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.