CM Custom Reports <= 1.2.7 - Authenticated (Administrator+) Stored Cross-Site Scripting via Plugin Labels
Description
The CM Custom Reports – Flexible reporting to track what matters most plugin for WordPress is vulnerable to Stored Cross-Site Scripting via admin settings in all versions up to, and including, 1.2.7 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with administrator-level permissions and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page. This only affects multi-site installations and installations where unfiltered_html has been disabled.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.2.7Source Code
WordPress.org SVNPatched version not available.
# Exploitation Research Plan: CVE-2026-2432 (CM Custom Reports) ## 1. Vulnerability Summary The **CM Custom Reports** plugin (versions <= 1.2.7) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The vulnerability exists in the plugin's "Labels" settings, which allow administrators to customiz…
Show full research plan
Exploitation Research Plan: CVE-2026-2432 (CM Custom Reports)
1. Vulnerability Summary
The CM Custom Reports plugin (versions <= 1.2.7) is vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability exists in the plugin's "Labels" settings, which allow administrators to customize text strings used throughout the plugin's interface. Because the plugin fails to sanitize these inputs when saved to the database and fails to escape them when rendered back to the UI, an attacker with administrative privileges can inject arbitrary JavaScript.
While administrators typically have the unfiltered_html capability, this vulnerability is significant in WordPress Multisite environments or installations where DISALLOW_UNFILTERED_HTML is defined, as it allows an administrator to bypass these security restrictions and execute scripts in the context of other users (including Super Admins).
2. Attack Vector Analysis
- Vulnerable Endpoint: Admin Settings Page (likely
admin.php?page=cmcr_settingsor similar). - Vulnerable Tab: "Labels" tab.
- Payload Carrier: POST parameters corresponding to label fields (e.g.,
cmcr_labels[some_label_key]). - Authentication: Required (Administrator+).
- Preconditions:
unfiltered_htmlmust be disabled for the user (e.g., via Multisite or configuration) to demonstrate a privilege escalation/security bypass, though the vulnerability exists regardless.
3. Code Flow (Inferred)
- Registration: The plugin registers a settings page using
add_submenu_page()under thecm-custom-reportsmenu. - Input Handling: On the "Labels" tab, the plugin provides a form. When the form is submitted, a handler (likely hooked to
admin_initoradmin_post) processes the$_POSTdata. - Persistence: The handler likely iterates through the labels and saves them using
update_option(). It fails to applysanitize_text_field()orwp_kses()to the label values. - Output: When the settings page or a report page is loaded, the plugin retrieves the labels using
get_option(). - Sink: The retrieved labels are echoed directly into the HTML without using
esc_html()oresc_attr().
4. Nonce Acquisition Strategy
To save settings, the plugin will require a WordPress nonce to prevent CSRF.
- Identify Page: Navigate to the CM Custom Reports settings page. The slug is likely
cmcr_settingsorcm-custom-reports-settings. - Access Page: Use the
browser_navigatetool to go tohttp://localhost:8080/wp-admin/admin.php?page=cmcr_settings. - Extract Nonce: CM plugins typically wrap their settings in a form that includes a standard WordPress nonce field.
- JS Extraction:
- Use
browser_evalto find the nonce:browser_eval("document.querySelector('input[name=\"_wpnonce\"]')?.value") - Also, check for specific CM localization objects:
browser_eval("window.cmcr_settings?.nonce")(inferred)
- Use
5. Exploitation Strategy
The goal is to store an XSS payload in a label and trigger it by viewing the settings page.
Step 1: Discover the Settings Form
Navigate to the settings page and inspect the "Labels" tab to identify the exact POST keys.
- URL:
/wp-admin/admin.php?page=cmcr_settings(inferred) - Tool:
browser_navigate
Step 2: Submit XSS Payload
Submit a POST request to the settings handler. Based on CM plugin patterns, this is often a direct POST to the same settings page or options.php.
- Target URL:
http://localhost:8080/wp-admin/admin.php?page=cmcr_settings - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters (Inferred):
_wpnonce: [Extracted Nonce]action:updatecmcr_labels[report_header]:<script>alert("XSS_STORED")</script>save:Save Changes
Step 3: Trigger Payload
Navigate back to the settings page or any page where the labels are rendered.
- URL:
/wp-admin/admin.php?page=cmcr_settings - Tool:
browser_navigate
6. Test Data Setup
- User: Ensure an Administrator user exists.
- Hardening: To prove the vulnerability's impact, disable
unfiltered_htmlfor the admin:wp-config.php:define( 'DISALLOW_UNFILTERED_HTML', true );
- Plugin State: Ensure CM Custom Reports (<= 1.2.7) is installed and activated.
7. Expected Results
- The HTTP response for the settings save should indicate a redirect (302) or success message.
- Upon navigating to the settings page, an alert box with
XSS_STOREDshould appear. - The page source should contain the literal string
<script>alert("XSS_STORED")</script>.
8. Verification Steps
- Database Check: Use WP-CLI to check the stored option:
wp option get cmcr_labels(inferred option name)
Verify that the output contains the raw<script>tag. - Source Check: Verify the rendered output via the browser:
browser_eval("document.body.innerHTML.includes('<script>alert')")
9. Alternative Approaches
- AJAX Handler: If the plugin saves via AJAX, look for a
wp_ajax_cmcr_save_labelsaction in the source code. - Report Rendering: If the XSS does not fire on the admin settings page, try viewing a generated report where the labels might be used as headers.
- Attribute Breakout: If the payload is rendered inside an input value, use:
"><script>alert(1)</script>orx" onmouseover="alert(1).
Summary
The CM Custom Reports plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'Labels' settings in versions up to 1.2.7. The plugin fails to sanitize user-inputted label text before saving it to the database and fails to escape the values when rendering them on the settings page, allowing administrators to execute arbitrary JavaScript in the context of other users.
Vulnerable Code
// Inferred from plugin architecture and research plan // File: views/backend/settings.php // Rendering the labels tab inputs foreach ($labels as $key => $value) { echo '<input type="text" name="cmcr_labels[' . $key . ']" value="' . $value . '">'; } --- // File: classes/Settings.php // Handling the settings save action if (isset($_POST['cmcr_labels'])) { $labels = $_POST['cmcr_labels']; update_option('cmcr_labels', $labels); // Fails to sanitize array values }
Security Fix
@@ -10,5 +10,5 @@ if (isset($_POST['cmcr_labels'])) { - $labels = $_POST['cmcr_labels']; + $labels = array_map('sanitize_text_field', $_POST['cmcr_labels']); update_option('cmcr_labels', $labels); } @@ -5,3 +5,3 @@ foreach ($labels as $key => $value) { - echo '<input type="text" name="cmcr_labels[' . $key . ']" value="' . $value . '">'; + echo '<input type="text" name="cmcr_labels[' . esc_attr($key) . ']" value="' . esc_attr($value) . '">'; }
Exploit Outline
The exploit targets the plugin's administrative settings interface where text labels can be customized. 1. Authentication: The attacker must be logged in as a WordPress Administrator. 2. Endpoint: Navigate to the CM Custom Reports settings page, specifically the 'Labels' tab (typically `admin.php?page=cmcr_settings`). 3. Payload: Identify a text input field for a label (e.g., a report header or button text) and inject a script payload such as: `<script>alert(document.cookie)</script>` or `"><script>alert(1)</script>`. 4. Persistence: Submit the form. The plugin saves the raw payload into the `cmcr_labels` option in the `wp_options` table. 5. Execution: The payload will execute whenever an administrator views the 'Labels' tab or whenever the plugin renders that specific label on the front-end or back-end, bypassing `unfiltered_html` restrictions in Multisite environments.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.