CVE-2026-2431

CM Custom Reports <= 1.2.7 - Reflected Cross-Site Scripting via 'date_from' and 'date_to' Parameters

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.1
CVSS Score
6.1
CVSS Score
medium
Severity
1.2.8
Patched in
1d
Time to patch

Description

The CM Custom Reports plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'date_from' and 'date_to' parameters in all versions up to, and including, 1.2.7 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that execute if they can successfully trick a user into performing an action such as clicking on a link.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
Required
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.2.7
PublishedMarch 6, 2026
Last updatedMarch 7, 2026
Affected plugincm-custom-reports

Source Code

WordPress.org SVN
Patched

Patched version not available.

Research Plan
Unverified

This research plan focuses on identifying and exploiting a reflected Cross-Site Scripting (XSS) vulnerability in the **CM Custom Reports** plugin (versions <= 1.2.7). ### 1. Vulnerability Summary The CM Custom Reports plugin fails to sufficiently sanitize and escape the `date_from` and `date_to` HT…

Show full research plan

This research plan focuses on identifying and exploiting a reflected Cross-Site Scripting (XSS) vulnerability in the CM Custom Reports plugin (versions <= 1.2.7).

1. Vulnerability Summary

The CM Custom Reports plugin fails to sufficiently sanitize and escape the date_from and date_to HTTP GET parameters before reflecting them in the HTML output. This allows an unauthenticated attacker to craft a malicious URL that, when clicked by a user (typically an administrator), executes arbitrary JavaScript in the context of that user's session.

2. Attack Vector Analysis

  • Vulnerable Endpoint: Likely an admin-side report dashboard or a frontend report page. Based on the plugin name, the primary target is likely wp-admin/admin.php?page=cm-custom-reports-dashboard (inferred slug) or similar.
  • Vulnerable Parameters: date_from and date_to.
  • Authentication Level: Reflected XSS generally requires a victim to be logged in if the reflection occurs on a protected page (like the admin dashboard). The CVSS vector PR:N suggests the endpoint might be accessible or the reflection occurs regardless of privileges, but the impact is highest when targeting an administrator.
  • Preconditions: The plugin must be active. The victim must click a link containing the XSS payload.

3. Code Flow (Inferred)

  1. Entry Point: A user accesses a report page via a GET request.
  2. Processing: The plugin retrieves the date filters:
    $date_from = isset($_GET['date_from']) ? $_GET['date_from'] : '';
    $date_to = isset($_GET['date_to']) ? $_GET['date_to'] : '';
    
  3. Reflection (Sink): The plugin echoes these values back into the HTML, likely inside an <input> field's value attribute for a date picker or a filter form:
    echo '<input type="text" name="date_from" value="' . $date_from . '">'; // VULNERABLE SINK
    
  4. Execution: If $date_from contains "><script>alert(1)</script>, the resulting HTML becomes:
    <input type="text" name="date_from" value=""><script>alert(1)</script>">
    

4. Nonce Acquisition Strategy

Reflected XSS in GET parameters used for display typically does not require a nonce. Nonces are used to protect against state-changing actions (CSRF). However, if the page is an admin page, the "exploit" consists of tricking an admin into visiting the URL.

If the plugin requires a nonce to even view the report page:

  1. Identify the variable: Use grep -r "wp_localize_script" . to find how the plugin passes data to JS.
  2. Extraction:
    • Create a page/post with the relevant report shortcode if applicable: wp post create --post_type=page --post_status=publish --post_content='[cm_custom_report]' (shortcode name inferred).
    • Navigate to the page as an admin using browser_navigate.
    • Execute browser_eval("window.cm_reports_data?.nonce") to extract it.

5. Exploitation Strategy

The goal is to demonstrate that JavaScript executes when the parameters are processed.

Payload: "><script>alert(document.domain)</script>
Encoded Payload: %22%3E%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E

Step-by-Step:

  1. Discovery: Identify the exact admin page slug for reports.
    • grep -r "add_menu_page" . or grep -r "add_submenu_page" .
  2. Manual Verification:
    • Use http_request to fetch the admin page as an administrator, including the payload in the date_from parameter.
  3. Refined Request:
    • Method: GET
    • URL: http://localhost:8080/wp-admin/admin.php?page=[PAGE_SLUG]&date_from=%22%3E%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E
    • Headers: Standard admin session cookies.

6. Test Data Setup

  1. Plugin Installation: Ensure cm-custom-reports v1.2.7 is installed and active.
  2. Administrative Access: The agent must have admin credentials to view the reflection in the admin dashboard.
  3. Sample Data: It may be helpful to generate some dummy report data so the report page renders fully:
    • wp post create --post_type=post --post_title='Sample Data' --post_status=publish

7. Expected Results

  • The HTTP response body should contain the unescaped string: value=""><script>alert(document.domain)</script>"
  • When viewed in a browser, a JavaScript alert showing the domain name should trigger.

8. Verification Steps

  1. Automated Check: Use the http_request tool and search the response body for the payload.
    # Example logic for the agent
    response = http_request(url="...")
    if '"><script>alert(document.domain)</script>' in response['body']:
        print("Vulnerability Confirmed: Reflection found without escaping.")
    
  2. Code Audit (Post-Exploit): Verify the sink in the source code using grep:
    grep -n "date_from" [FILE_PATH] -A 5 | grep "echo"
    

9. Alternative Approaches

  • Attribute Breakout: If the value is inside a hidden input or a specific JS block, try:
    • ' onmouseover='alert(1) (if in a visible attribute).
    • -alert(1)- (if inside a JS numeric assignment).
  • Parameter date_to: If date_from is sanitized (unlikely), test the date_to parameter as it often shares the same logic.
  • Unauthenticated Check: Check if the reflection occurs on the login page or a public-facing page (e.g., if the plugin handles reports via admin-ajax.php or wp-load.php entry points).
Research Findings
Static analysis — not yet PoC-verified

Summary

The CM Custom Reports plugin for WordPress (versions <= 1.2.7) is vulnerable to Reflected Cross-Site Scripting due to insufficient input sanitization and output escaping on the 'date_from' and 'date_to' parameters. An attacker can execute arbitrary JavaScript in the context of a victim's browser session, typically an administrator, by tricking them into clicking a malicious link.

Vulnerable Code

// File: views/backend/reports.php (inferred context)
$date_from = isset($_GET['date_from']) ? $_GET['date_from'] : '';
$date_to = isset($_GET['date_to']) ? $_GET['date_to'] : '';

// ... further down in the file where the filter form is rendered ...

?>
<div class="filter-container">
    <input type="text" name="date_from" value="<?php echo $date_from; ?>" class="datepicker" />
    <input type="text" name="date_to" value="<?php echo $date_to; ?>" class="datepicker" />
</div>
<?php

Security Fix

--- views/backend/reports.php
+++ views/backend/reports.php
@@ -10,8 +10,8 @@
- $date_from = isset($_GET['date_from']) ? $_GET['date_from'] : '';
- $date_to = isset($_GET['date_to']) ? $_GET['date_to'] : '';
+ $date_from = isset($_GET['date_from']) ? sanitize_text_field($_GET['date_from']) : '';
+ $date_to = isset($_GET['date_to']) ? sanitize_text_field($_GET['date_to']) : '';
 
- <input type="text" name="date_from" value="<?php echo $date_from; ?>" class="datepicker" />
- <input type="text" name="date_to" value="<?php echo $date_to; ?>" class="datepicker" />
+ <input type="text" name="date_from" value="<?php echo esc_attr($date_from); ?>" class="datepicker" />
+ <input type="text" name="date_to" value="<?php echo esc_attr($date_to); ?>" class="datepicker" />

Exploit Outline

1. Identify the CM Custom Reports dashboard or report generation page in the WordPress admin area (typically under a menu like 'CM Custom Reports'). 2. Construct a malicious URL targeting this page, appending the 'date_from' or 'date_to' GET parameters with a payload designed to break out of an HTML attribute, such as: `"><script>alert(document.domain)</script>`. 3. The full attack URL would look like: `http://example.com/wp-admin/admin.php?page=cm-custom-reports-dashboard&date_from=%22%3E%3Cscript%3Ealert(document.domain)%3C/script%3E`. 4. Persuade a logged-in administrator to click the link through social engineering (e.g., an email or support ticket). 5. When the administrator visits the link, the plugin reflects the malicious script into the input field's value attribute without escaping, causing the browser to execute the script in the administrator's context.

Check if your site is affected.

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