CVE-2026-7525

My Calendar <= 3.7.9 - Authenticated (Custom+) Missing Authorization to Unauthorized Event Publication via 'event_approved' Parameter

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
3.7.10
Patched in
1d
Time to patch

Description

The My Calendar – Accessible Event Manager plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 3.7.9. This is due to the plugin not properly verifying that a user is authorized to perform an action. This makes it possible for authenticated attackers, with custom-level access and above, to bypass the moderation and approval workflow by tampering with the POST body to publish events or set other unauthorized statuses such as cancelled or private, in ways their role does not permit. While the UI correctly restricts low-privilege users to a draft-only submit button, this restriction is enforced only client-side, making it trivially bypassable by directly manipulating the POST request.

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.7.9
PublishedMay 13, 2026
Last updatedMay 14, 2026
Affected pluginmy-calendar

What Changed in the Fix

Changes introduced in v3.7.10

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Vulnerability Research Plan: CVE-2026-7525 ## 1. Vulnerability Summary The **My Calendar** plugin for WordPress is vulnerable to a missing authorization check in versions up to and including **3.7.9**. While the administrative UI restricts low-privilege users (those with "Custom" access like `mc_…

Show full research plan

Vulnerability Research Plan: CVE-2026-7525

1. Vulnerability Summary

The My Calendar plugin for WordPress is vulnerable to a missing authorization check in versions up to and including 3.7.9. While the administrative UI restricts low-privilege users (those with "Custom" access like mc_add_events) to only submitting drafts for review, the backend fails to validate if the user has the authority to set the event_approved status. By intercepting and modifying the POST request during event creation or editing, an authenticated attacker can bypass the moderation workflow to directly publish events (event_approved=1) or set other unauthorized statuses.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin.php?page=my-calendar (Administrative event management page)
  • Vulnerable Parameter: event_approved
  • Required Authentication: Authenticated user with at least mc_add_events capability (Custom level).
  • Payload Type: Form-data (POST body)
  • Preconditions: The user must be logged in and have permission to access the "Add Event" or "Edit Event" page.

3. Code Flow

  1. Entry Point: A user accesses the "Add Event" page (admin.php?page=my-calendar&mode=add).
  2. Submission: The user submits the event form. The browser sends a POST request to the same URL or the management handler.
  3. Processing (Inferred): The plugin processes the submission (likely in a function handling mode=add or mode=edit).
  4. Missing Check: The code extracts $_POST['event_approved']. While the UI only provides a button that sends event_approved=0 (Draft) for low-privilege users, the backend code fails to call current_user_can( 'mc_approve_events' ) before assigning the event_approved value to the event object being saved to the database.
  5. Sink: The my_calendar_event_table is updated with the user-supplied event_approved value.

4. Nonce Acquisition Strategy

My Calendar uses standard WordPress nonces for its admin forms. To obtain a valid nonce for the "Add Event" action:

  1. Login: Use the security agent to log in as a user with the mc_add_events capability.
  2. Navigate: Navigate to the "Add Event" page: /wp-admin/admin.php?page=my-calendar&mode=add.
  3. Extract: Use browser_eval to extract the nonce and standard form values.
    • The nonce is typically in a hidden input named _wpnonce.
    • Command: browser_eval("document.querySelector('input[name=\"_wpnonce\"]').value")

5. Exploitation Strategy

The goal is to create a published event as a user who should only be allowed to create drafts.

  1. Setup User: Create a user with the Subscriber role and grant them the mc_add_events capability using WP-CLI.
  2. Capture Form Data:
    • Navigate to /wp-admin/admin.php?page=my-calendar&mode=add.
    • Extract the _wpnonce.
    • Identify other required fields: event_title, event_begin, event_time, event_end, event_endtime.
  3. Craft Malicious POST:
    • Submit a POST request to /wp-admin/admin.php?page=my-calendar.
    • Include mode=add.
    • Include event_title=Malicious Published Event.
    • Set event_approved=1 (The bypass).
    • Include required dates/times (e.g., event_begin=2025-10-10, event_time=12:00:00).
  4. Execute Request: Use the http_request tool to send the authenticated POST request.

Example Payload (POST Body):

_wpnonce=[NONCE]&mode=add&event_title=Bypassed+Event&event_desc=This+event+should+be+a+draft&event_begin=2025-01-01&event_time=12%3A00%3A00&event_end=2025-01-01&event_endtime=13%3A00%3A00&event_approved=1&save=Add+Event

6. Test Data Setup

  1. Plugin Activation: Ensure "My Calendar" is active.
  2. Create Attacker User:
    wp user create attacker attacker@example.com --role=subscriber --user_pass=password
    
  3. Grant Permissions: Grant the specific My Calendar capability. My Calendar maps its internal capabilities to WordPress roles/caps.
    # Granting the capability required to add events
    wp user add-cap attacker mc_add_events
    
  4. Confirm Permissions: Ensure the user can reach the "Add Event" page but cannot "Approve" (published status).

7. Expected Results

  • The server should respond with a 302 Redirect (standard WordPress admin behavior) or a success message indicating the event was added.
  • The event should be visible on the public calendar immediately without administrative approval.
  • Checking the database will show event_approved = 1.

8. Verification Steps

  1. Check Database:
    wp db query "SELECT event_title, event_approved FROM $(wp db prefix)my_calendar WHERE event_title = 'Bypassed Event'"
    
    • Success Criteria: event_approved is 1.
  2. Check Visibility:
    • Use mc_event_published logic (from includes/conditionals.php) or simply check the front-end calendar page if it exists.
    • Navigate to the homepage/calendar page and verify the "Bypassed Event" title appears.

9. Alternative Approaches

  • Edit Existing Draft: If "Add Event" is hardened, attempt to edit an existing draft event (mode=edit&event_id=X) and change event_approved from 0 to 1.
  • Unauthorized Statuses: Instead of 1 (Published), attempt to set event_approved to 2 (Draft/Pending), 3 (Cancelled), or 4 (Hidden/Private) to disrupt site operations.
  • AJAX Endpoint: Check if admin-ajax.php handlers exist for event saving that might also be missing authorization checks for the event_approved field. (Check includes/class-mc-ajax.php if present in full source).
Research Findings
Static analysis — not yet PoC-verified

Summary

The My Calendar plugin for WordPress is vulnerable to an authorization bypass where authenticated users with event creation permissions can directly publish events by tampering with the 'event_approved' POST parameter. Because the plugin only enforces the moderation workflow on the client-side (via UI buttons) and lacks a server-side capability check for event approval, users can bypass administrative review to publish, cancel, or hide events.

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/my-calendar/3.7.9/css/mc-styles.css /home/deploy/wp-safety.org/data/plugin-versions/my-calendar/3.7.10/css/mc-styles.css
--- /home/deploy/wp-safety.org/data/plugin-versions/my-calendar/3.7.9/css/mc-styles.css	2026-04-26 23:23:00.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/my-calendar/3.7.10/css/mc-styles.css	2026-05-10 15:24:34.000000000 +0000
@@ -306,9 +306,13 @@
 
 #event_date_error.visible {
 	opacity: 1;
+	display: flex;
+	align-items: center;
 }
 
-#event_date_error .dashicons {
+#event_date_error.visible::before {
+	content: "\f158";
+	font-family: dashicons;
 	color: #a00;
 }
 
@@ -316,6 +320,11 @@
 	opacity: 0;
 }
 
+#my-calendar .duet-date__input {
+	border-radius: 0 !important;
+	padding: 11px 60px 10px 14px;
+}
+
 #e_schedule .columns label:not(.duet-date__mobile-heading),
 .recurrences .columns label:not(.duet-date__mobile-heading),
 .recurring .columns label:not(.duet-date__mobile-heading) {
@@ -323,6 +332,12 @@
 	max-width: fit-content;
 }
 
+.recurrences-disabled {
+	display: flex;
+	align-items: center;
+	gap: .5rem;
+}
+
 #e_schedule .columns .checkboxes label {
 	display: inline;
 }
@@ -345,18 +360,6 @@
 	outline-offset: 2px;
 }
 
-.recurrences input[type=time],
-#e_schedule input[type=time],
-.my-calendar-admin input[type=date],
-.recurring select {
-	padding: 8px 24px 8px 8px;
-}
-
-.recurring input[type=number] {
-	padding: 8px;
-	width: 5em;
-}
-
 #event1 .new-field {
 	display: none;
 }
@@ -367,11 +370,9 @@
 }
 
 p.event_span.checkboxes {
-	border: 1px solid #c3c4c7;
-	border-radius: 3px;
-	padding: 1em 1em .5em;
-	background: #f0f0f1;
-	margin-bottom: 1em;
+	padding: 1em;
+	background: rgba( 0, 0, 0, .04 );
+	align-items: center;
 }
 
 ol.mc-repeat-events {
@@ -1614,10 +1615,6 @@
 	line-height: normal;
 }
 
-select[name="event_recur"] {
-	vertical-align: top;
-}
-
 .my-calendar-admin li.events_access_notes {
 	padding: 0px 1px 1px 5px;
 	gap: 5px;
... (truncated)

Exploit Outline

To exploit this vulnerability, an attacker must have an account with permissions to add events (e.g., the 'mc_add_events' capability). The attacker first logs into the WordPress admin panel and navigates to the 'Add Event' page (`admin.php?page=my-calendar&mode=add`) to retrieve a valid security nonce (`_wpnonce`). They then craft a POST request to the same endpoint, providing all necessary event details (title, description, dates, times). By adding the parameter `event_approved=1` to the POST body, the attacker overrides the default draft status. Upon submission, the plugin accepts the user-provided approval status without verifying if the user has the 'mc_approve_events' capability, resulting in the event being published immediately on the public-facing calendar.

Check if your site is affected.

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