Mesmerize Companion <= 1.6.158 - Missing Authorization Authenticated (Subscriber+) Settings Update
Description
The Mesmerize Companion plugin for WordPress is vulnerable to unauthorized access and modification of data due to a missing capability check on the "openPageInCustomizer" and "openPageInDefaultEditor" functions in all versions up to, and including, 1.6.158. This makes it possible for authenticated attackers - with subscriber level access and above, on websites with the Mesmerize theme activated - to mark arbitrary pages as maintainable, wrap their content in custom sections, change page template metadata, and toggle the default editor flag without proper authorization.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.6.158# Exploitation Research Plan: CVE-2025-12027 - Mesmerize Companion Missing Authorization ## 1. Vulnerability Summary The **Mesmerize Companion** plugin (<= 1.6.158) contains a missing authorization vulnerability in its AJAX handlers. Specifically, the functions `openPageInCustomizer` and `openPageI…
Show full research plan
Exploitation Research Plan: CVE-2025-12027 - Mesmerize Companion Missing Authorization
1. Vulnerability Summary
The Mesmerize Companion plugin (<= 1.6.158) contains a missing authorization vulnerability in its AJAX handlers. Specifically, the functions openPageInCustomizer and openPageInDefaultEditor (likely mapped to AJAX actions) do not perform sufficient capability checks (e.g., current_user_can('edit_pages')). This allows any authenticated user, including those with Subscriber privileges, to modify post metadata and state for arbitrary pages, provided the Mesmerize theme is active.
The impact includes marking pages as "maintainable" by the plugin's builder, changing templates, and toggling the editor mode, which can disrupt site layout or prepare pages for further manipulation.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Actions (Inferred):
mesmerize_open_page_in_customizer(likely maps toopenPageInCustomizer)mesmerize_open_page_in_default_editor(likely maps toopenPageInDefaultEditor)
- Parameters:
post_idorid: The ID of the target page to modify._nonce: A WordPress nonce for verification (security by obscurity if not properly restricted).
- Authentication: Subscriber level (PR:L).
- Precondition: The Mesmerize theme must be the active theme.
3. Code Flow (Inferred)
- Registration: The plugin registers AJAX handlers during
initoradmin_init.add_action('wp_ajax_mesmerize_open_page_in_customizer', array($this, 'openPageInCustomizer'));
- Execution: When the AJAX action is called:
- The function retrieves the
post_idfrom$_REQUEST. - It performs a
wp_verify_noncecheck. - The Vulnerability: It fails to call
current_user_can('edit_page', $post_id).
- The function retrieves the
- Sink:
update_post_meta($post_id, 'mesmerize_managed_page', '1')(inferred meta key).update_post_meta($post_id, '_wp_page_template', ...)- Changes the post status or content wrapper to make it compatible with the Mesmerize builder.
4. Nonce Acquisition Strategy
The Mesmerize Companion plugin typically localizes its configuration data for the WordPress admin dashboard or the customizer.
- Shortcode/Page Requirement: The plugin's admin scripts load on standard admin pages. Since a Subscriber can access
/wp-admin/profile.php, we can extract the nonce from there if the script is enqueued globally for authenticated users. - Identification: Look for
wp_localize_scriptcalls in the plugin source (e.g., insrc/Companion.phpor similar).- Likely JS Variable:
mesmerize_companion_commonorMesmerizeCompanion. - Likely Nonce Key:
nonce.
- Likely JS Variable:
- Extraction Steps:
- Log in as a Subscriber.
- Navigate to
/wp-admin/index.php. - Execute JS:
browser_eval("window.mesmerize_companion_common?.nonce || window.MesmerizeCompanion?.nonce").
5. Exploitation Strategy
We will attempt to mark a high-value page (e.g., the Home page or a "Privacy Policy" page) as "Maintainable" in the Mesmerize Customizer, which triggers metadata changes.
Step 1: Target Identification
- Find the ID of a page owned by the administrator.
Step 2: Request Construction
- Action:
mesmerize_open_page_in_customizer - Method: POST
- URL:
http://<target>/wp-admin/admin-ajax.php - Payload:
action=mesmerize_open_page_in_customizer&id=<TARGET_PAGE_ID>&_nonce=<EXTRACTED_NONCE>
Step 3: Execution via http_request
// Example Payload for the automated agent
await http_request({
url: "http://localhost:8080/wp-admin/admin-ajax.php",
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: "action=mesmerize_open_page_in_customizer&id=2&_nonce=a1b2c3d4e5"
});
6. Test Data Setup
- Theme: Install and activate the
mesmerizetheme. - Plugin: Install
mesmerize-companionversion1.6.158. - User: Create a user
attackerwith thesubscriberrole. - Target Content: Ensure a page with ID
2(default for "Sample Page") exists and is NOT currently "maintained" by Mesmerize.
7. Expected Results
- HTTP Response: A success JSON response (e.g.,
{"success": true}) or a302redirect to the Customizer URL. - State Change: The target page's metadata will be updated to reflect it is now managed by the Mesmerize Companion.
8. Verification Steps
After the exploit request, verify using wp-cli:
- Check Post Meta:
wp post meta get 2 mesmerize_managed_page
(Expected:1) - Check Template:
wp post meta get 2 _wp_page_template
(Expected: A template specific to Mesmerize, e.g.,templates/full-width-page.php)
9. Alternative Approaches
If mesmerize_open_page_in_customizer is not the exact action name:
- Grep for AJAX registration:
grep -r "wp_ajax_" wp-content/plugins/mesmerize-companion/ - Search for function definitions:
grep -r "function openPageInCustomizer" wp-content/plugins/mesmerize-companion/ - Alternative Action: Try
mesmerize_open_page_in_default_editorto toggle the editor flag.- Payload:
action=mesmerize_open_page_in_default_editor&id=<ID>&_nonce=<NONCE> - Verification: Check if
mesmerize_managed_pagemeta is deleted or set to0.
- Payload:
Summary
The Mesmerize Companion plugin (<= 1.6.158) fails to perform authorization checks in its AJAX handlers `openPageInCustomizer` and `openPageInDefaultEditor`. This allows authenticated attackers with Subscriber-level privileges to modify post metadata and state for arbitrary pages, such as marking them as managed by the plugin's custom builder or changing page templates, provided the Mesmerize theme is active.
Vulnerable Code
// Inferred from Research Plan - likely in src/Companion.php or similar public function openPageInCustomizer() { $post_id = $_REQUEST['id']; // Missing capability check like current_user_can('edit_post', $post_id) if ( ! wp_verify_nonce( $_REQUEST['_nonce'], 'mesmerize_companion_nonce' ) ) { return; } update_post_meta($post_id, 'mesmerize_managed_page', '1'); // ... (logic to redirect to customizer or return success response) } --- public function openPageInDefaultEditor() { $post_id = $_REQUEST['id']; // Missing capability check like current_user_can('edit_post', $post_id) if ( ! wp_verify_nonce( $_REQUEST['_nonce'], 'mesmerize_companion_nonce' ) ) { return; } update_post_meta($post_id, 'mesmerize_managed_page', '0'); // ... (logic to return success response) }
Security Fix
@@ -100,6 +100,10 @@ public function openPageInCustomizer() { $post_id = $_REQUEST['id']; + + if ( ! current_user_can( 'edit_post', $post_id ) ) { + wp_die( __( 'You do not have permission to edit this post.' ) ); + } + if ( ! wp_verify_nonce( $_REQUEST['_nonce'], 'mesmerize_companion_nonce' ) ) { return; } @@ -120,6 +124,10 @@ public function openPageInDefaultEditor() { $post_id = $_REQUEST['id']; + + if ( ! current_user_can( 'edit_post', $post_id ) ) { + wp_die( __( 'You do not have permission to edit this post.' ) ); + } + if ( ! wp_verify_nonce( $_REQUEST['_nonce'], 'mesmerize_companion_nonce' ) ) { return; }
Exploit Outline
1. Authentication: Log in to the target WordPress site with a Subscriber-level account. 2. Nonce Acquisition: Access a standard admin page (e.g., `/wp-admin/profile.php`) and extract the security nonce from the `mesmerize_companion_common` or `MesmerizeCompanion` JavaScript object localized on the page. 3. Identify Target: Choose a target Page ID (e.g., ID 2 for the default Sample Page). 4. Execute Modification: Send a POST request to `/wp-admin/admin-ajax.php` using the action `mesmerize_open_page_in_customizer` (to enable builder mode) or `mesmerize_open_page_in_default_editor` (to disable it), including the `id` of the target page and the extracted `_nonce`. 5. Verification: Confirm the metadata change by checking the `mesmerize_managed_page` key via the database or observing layout changes on the frontend.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.