The Events Calendar <= 6.15.13 - Missing Authorization to Authenticated (Subscriber+) Data Migration Control
Description
The The Events Calendar plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on the 'start_migration', 'cancel_migration', and 'revert_migration' functions in all versions up to, and including, 6.15.13. This makes it possible for authenticated attackers, with subscriber level access and above, to start, cancel, or revert the Custom Tables V1 database migration, including dropping the custom database tables entirely via the revert action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:LTechnical Details
<=6.15.13Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2025-15043 (The Events Calendar) ## 1. Vulnerability Summary The **The Events Calendar** plugin (up to 6.15.13) contains a missing authorization vulnerability in its Custom Tables V1 migration logic. Specifically, the functions `start_migration`, `cancel_migration`…
Show full research plan
Exploitation Research Plan: CVE-2025-15043 (The Events Calendar)
1. Vulnerability Summary
The The Events Calendar plugin (up to 6.15.13) contains a missing authorization vulnerability in its Custom Tables V1 migration logic. Specifically, the functions start_migration, cancel_migration, and revert_migration fail to perform adequate capability checks (e.g., current_user_can( 'manage_options' )). While they may implement nonce verification, the nonces are often exposed to any authenticated user within the WordPress admin dashboard. This allows a Subscriber-level user to manipulate the core database state of the plugin, potentially leading to data loss via the revert_migration action, which drops custom database tables.
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Action Names (Inferred):
tribe_custom_tables_v1_start_migrationtribe_custom_tables_v1_cancel_migrationtribe_custom_tables_v1_revert_migration
- HTTP Method:
POST - Authentication: Authenticated (Subscriber or higher).
- Vulnerable Parameters:
actionandnonce. - Preconditions: The site must be using (or eligible for) the Custom Tables V1 migration.
3. Code Flow
- Entry Point: A logged-in user sends a request to
admin-ajax.phpwith one of the migration actions. - Hook Registration: The plugin registers AJAX handlers using
add_action( 'wp_ajax_...' ). - Vulnerable Functions: These are likely located within a migration-specific class, such as
Tribe\Events\Custom_Tables\V1\Migration\Admin_Handleror similar. - Processing:
- The handler calls
check_ajax_referer( 'tribe_custom_tables_v1_migration_action', 'nonce' )(inferred action string). - The Bug: After the nonce check, the code immediately calls the migration logic without verifying if the user has
manage_optionsortec_manage_settingscapabilities.
- The handler calls
- Sink: The
revert_migrationfunction executes SQL commands likeDROP TABLEon the custom events tables.
4. Nonce Acquisition Strategy
The migration logic is an admin feature. WordPress enqueues the necessary scripts and localizes the nonces for these actions in the admin dashboard.
- Identify the Script: Look for
wp_localize_scriptcalls that include the migration nonce. - Target Variable (Inferred): Search for
tribe_migration_v1ortribe_events_migration. - Execution Steps:
- Log in as a Subscriber.
- Navigate to the WordPress Dashboard (
/wp-admin/index.php). Most global plugin scripts are loaded across the admin area. - Use
browser_evalto extract the nonce:// Example based on typical plugin patterns window.tribe_migration_data?.nonce // OR window.TribeEventsMigration?.nonce - If the script is only loaded on specific pages, search for where
wp_enqueue_scriptis called for the migration UI and navigate there.
5. Exploitation Strategy
Goal: Trigger revert_migration as a Subscriber to drop custom tables.
Step 1: Discover Exact Action and Nonce:
- Search the codebase for
add_action( 'wp_ajax_combined withmigration. - Identify the nonce action string used in
check_ajax_referer. - Identify the JS object name used in
wp_localize_script.
- Search the codebase for
Step 2: Session Setup:
- Authenticate as a Subscriber and save cookies.
Step 3: Extract Nonce:
- Use
browser_navigateto/wp-admin/index.php. - Use
browser_evalto fetch the nonce from the identified JS object.
- Use
Step 4: Execute Revert Action:
- Send a POST request to
admin-ajax.php:- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=tribe_custom_tables_v1_revert_migration&nonce=[EXTRACTED_NONCE](Adjust action name based on Step 1).
- URL:
- Send a POST request to
6. Test Data Setup
- Install Plugin: Install The Events Calendar version 6.15.0 (vulnerable).
- Populate Events: Create 5-10 events to ensure there is data to migrate.
- Enable Custom Tables: Ensure the Custom Tables migration has been completed or is in a state where "Revert" is a valid state.
- Note: You may need to use
wp tribe migrations migratevia CLI to reach the state whererevertis possible.
- Note: You may need to use
- Create Attacker:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123.
7. Expected Results
- Response: The AJAX endpoint should return a success message (e.g.,
{"success":true}) or a200 OKindicating the migration process was altered. - Database Impact: The custom tables (e.g.,
wp_tec_occurrences,wp_tec_event_meta) should be dropped or flagged for deletion.
8. Verification Steps
- Database Check:
- Before exploit:
wp db query "SHOW TABLES LIKE '%tec_%'"should show custom tables. - After exploit: Run the same command; the tables should be missing.
- Before exploit:
- Option Check:
wp option get tribe_custom_tables_migration_statusshould reflect a "reverting" or "cancelled" state.
9. Alternative Approaches
- Start Migration: If "Revert" is not available, try
start_migration. This will trigger a resource-intensive background process, which is a form of Denial of Service (DoS)/Integrity violation. - REST API: Check if the plugin registered REST API endpoints for migration (
/wp-json/tribe/v1/migration/...). If so, check for apermission_callbackthat returnstrueor fails to check capabilities. These would use thewp_restnonce instead.
Summary
The Events Calendar plugin fails to implement capability checks on several AJAX handlers responsible for database migration tasks. Authenticated attackers with Subscriber-level access can exploit this to start, cancel, or revert the Custom Tables V1 migration, which can result in the deletion of custom database tables.
Vulnerable Code
// src/Tribe/Custom_Tables/V1/Migration/Admin_Handler.php public function action_start_migration() { check_ajax_referer( 'tribe_custom_tables_v1_migration_action', 'nonce' ); // Bug: No current_user_can() check before sensitive operation $this->migration->start(); wp_send_json_success(); } --- // src/Tribe/Custom_Tables/V1/Migration/Admin_Handler.php public function action_cancel_migration() { check_ajax_referer( 'tribe_custom_tables_v1_migration_action', 'nonce' ); // Bug: No current_user_can() check before sensitive operation $this->migration->cancel(); wp_send_json_success(); } --- // src/Tribe/Custom_Tables/V1/Migration/Admin_Handler.php public function action_revert_migration() { check_ajax_referer( 'tribe_custom_tables_v1_migration_action', 'nonce' ); // Bug: No current_user_can() check before sensitive operation $this->migration->revert(); wp_send_json_success(); }
Security Fix
@@ -24,6 +24,10 @@ public function action_start_migration() { check_ajax_referer( 'tribe_custom_tables_v1_migration_action', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 ); + } + $this->migration->start(); wp_send_json_success(); } @@ -34,6 +38,10 @@ public function action_cancel_migration() { check_ajax_referer( 'tribe_custom_tables_v1_migration_action', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 ); + } + $this->migration->cancel(); wp_send_json_success(); } @@ -44,6 +52,10 @@ public function action_revert_migration() { check_ajax_referer( 'tribe_custom_tables_v1_migration_action', 'nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( [ 'message' => 'Unauthorized' ], 403 ); + } + $this->migration->revert(); wp_send_json_success(); }
Exploit Outline
1. Authenticate to the WordPress site as a user with Subscriber-level permissions or higher. 2. Access the WordPress admin dashboard (e.g., /wp-admin/) and inspect the page source or localized JavaScript objects to retrieve the migration nonce (likely stored in a variable such as `tribe_migration_data.nonce`). 3. Send a POST request to `/wp-admin/admin-ajax.php` with the parameter `action=tribe_custom_tables_v1_revert_migration` and the extracted nonce. 4. The plugin will execute the `revert` logic, dropping the custom database tables (e.g., `wp_tec_occurrences`) without verifying that the requesting user has administrative privileges.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.