MDJM Event Management <= 1.7.8.1 - Missing Authorization to Unauthenticated Arbitrary Custom Event Field Deletion
Description
The MDJM Event Management plugin for WordPress is vulnerable to unauthorized data modification due to a missing capability check on the 'custom_fields_controller' function in all versions up to, and including, 1.7.8.1. This makes it possible for unauthenticated attackers to delete arbitrary custom event fields via the 'delete_custom_field' and 'id' parameters.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.7.8.1What Changed in the Fix
Changes introduced in v1.7.8.2
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-1650 ## 1. Vulnerability Summary The **MDJM Event Management** plugin (versions up to 1.7.8.1) is vulnerable to unauthenticated arbitrary custom event field deletion. The vulnerability exists in the `MDJM_Event_Fields` class located in `includes/admin/pages/ev…
Show full research plan
Exploitation Research Plan: CVE-2026-1650
1. Vulnerability Summary
The MDJM Event Management plugin (versions up to 1.7.8.1) is vulnerable to unauthenticated arbitrary custom event field deletion. The vulnerability exists in the MDJM_Event_Fields class located in includes/admin/pages/event-fields.php. The class registers a controller function, custom_fields_controller(), to the admin_init hook. Because admin_init fires on admin-ajax.php even for unauthenticated users, and the controller lacks any capability checks (current_user_can) or nonce verification (check_admin_referer), an attacker can trigger the delete_field() method by providing specific GET parameters.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php(triggersadmin_initunauthenticated) - Method:
GET - Vulnerable Hook:
admin_init - Vulnerable Function:
MDJM_Event_Fields::custom_fields_controller - Required Parameters:
delete_custom_field: Must be present in$_GET.id: The integer ID of the custom field (post ID) to be deleted.
- Authentication: None (Unauthenticated).
- Preconditions: An attacker must know or brute-force the ID of an existing custom event field (which uses the custom post type
mdjm-custom-fields).
3. Code Flow
- Entry Point: A request is made to
/wp-admin/admin-ajax.php. - Hook Trigger: WordPress initializes the admin environment, firing the
admin_inithook. - Registration: In
includes/admin/pages/event-fields.php, the constructor ofMDJM_Event_Fieldsregisters the handler:add_action('admin_init', array(&$this, 'custom_fields_controller')); - Logic Branch: The
custom_fields_controller()function executes:function custom_fields_controller() { // ... (POST logic for add/update) if (isset($_GET['delete_custom_field'], $_GET['id'])) { $this->delete_field(); } return; } - Sink: The
delete_field()function is called. While the full source ofdelete_fieldis truncated in the provided snippet, the vulnerability description confirms it performs the deletion based on theidparameter without further authorization.
4. Nonce Acquisition Strategy
No nonce is required.
The code path in custom_fields_controller() for the GET parameters delete_custom_field and id does not invoke check_admin_referer() or wp_verify_nonce(). The missing authorization is the core of this vulnerability.
5. Exploitation Strategy
The exploit involves sending an unauthenticated GET request to the WordPress admin-ajax endpoint with the target parameters.
Step-by-Step Plan:
- Identify Target ID: Determine the ID of an existing custom event field (type
mdjm-custom-fields). - Execute Deletion: Use the
http_requesttool to send the malicious GET request. - Verify: Use WP-CLI to confirm the post has been deleted.
Malicious Request:
- URL:
http://localhost:8080/wp-admin/admin-ajax.php?delete_custom_field=1&id=[TARGET_ID] - Method:
GET - Headers: None required.
6. Test Data Setup
To test the vulnerability, a custom field must first be created.
- Create a Custom Event Field via WP-CLI:
wp post create --post_type=mdjm-custom-fields --post_title="Sensitive Field" --post_status=publish --post_content="Description" - Record the ID: The command above will return the ID (e.g.,
123). This is your[TARGET_ID].
7. Expected Results
- Response: The server will likely return a 200 OK or a redirect (depending on whether the
delete_fieldfunction callswp_safe_redirectas seen in other functions in the class), but the key outcome is the background execution of the deletion. - Data State: The post with ID
[TARGET_ID]and post_typemdjm-custom-fieldsshould no longer exist or should be moved to the trash (depending on thewp_delete_postimplementation indelete_field).
8. Verification Steps
After sending the HTTP request, verify the deletion using WP-CLI:
# Check if the post still exists
wp post list --post_type=mdjm-custom-fields --post_status=any --include=[TARGET_ID]
If the command returns an empty list or doesn't show the [TARGET_ID], the exploit was successful.
9. Alternative Approaches
If /wp-admin/admin-ajax.php is blocked or fails to trigger the hook as expected, any other admin file that triggers admin_init can be targeted, provided the user is not automatically redirected. Examples:
/wp-admin/admin-post.php?delete_custom_field=1&id=[TARGET_ID]/wp-admin/index.php?delete_custom_field=1&id=[TARGET_ID](Note: This may require a valid login session to bypass theis_user_logged_in()check inadmin.php, whereasadmin-ajax.phpusually bypasses it for AJAX compatibility).
Since the vulnerability is unauthenticated, admin-ajax.php is the primary and most reliable vector.
Summary
The MDJM Event Management plugin for WordPress is vulnerable to unauthenticated arbitrary custom event field deletion due to a missing capability check and nonce verification on the custom_fields_controller function. This allows attackers to delete custom post types associated with event fields by sending a simple GET request to any administrative endpoint, including admin-ajax.php.
Vulnerable Code
// includes/admin/pages/event-fields.php line 17 function __construct() { add_action('admin_init', array(&$this, 'custom_fields_controller')); add_action('mdjm_add_content_tags', array(&$this, 'add_tags')); // ... } --- // includes/admin/pages/event-fields.php line 104 function custom_fields_controller() { if (isset($_POST['submit_custom_field'])) { if ($_POST['submit_custom_field'] == __('Add Field', 'mobile-dj-manager')) { $this->add_field(); } elseif ($_POST['submit_custom_field'] == __('Save Changes', 'mobile-dj-manager')) { $this->update_field(); } } if (isset($_GET['delete_custom_field'], $_GET['id'])) { $this->delete_field(); } return; } // custom_fields_controller
Security Fix
@@ -104,6 +104,10 @@ function custom_fields_controller() { + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + if (isset($_POST['submit_custom_field'])) { if ($_POST['submit_custom_field'] == __('Add Field', 'mobile-dj-manager')) { $this->add_field(); @@ -115,6 +119,8 @@ } if (isset($_GET['delete_custom_field'], $_GET['id'])) { + check_admin_referer( 'mdjm_delete_custom_field_' . $_GET['id'] ); + $this->delete_field(); } return;
Exploit Outline
1. Identify the post ID of a custom event field (typically using the 'mdjm-custom-fields' post type). 2. Construct a GET request to the WordPress admin environment (e.g., /wp-admin/admin-ajax.php) including the parameters 'delete_custom_field=1' and 'id' set to the target post ID. 3. Send the request without any authentication headers or session cookies. 4. The plugin's custom_fields_controller function, which is hooked to admin_init, will execute and call the delete_field method without verifying the user's identity or authorization level. 5. Observe that the custom event field is successfully deleted or moved to the trash.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.