CVE-2026-5226

Optimole <= 4.2.3 - Reflected Cross-Site Scripting via Page Profiler URL

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

Description

The Optimole – Optimize Images in Real Time plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via URL paths in versions up to, and including, 4.2.3 This is due to insufficient output escaping on user-supplied URL paths in the get_current_url() function, which are inserted into JavaScript code via str_replace() without proper JavaScript context escaping in the replace_content() function. 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<=4.2.3
PublishedApril 10, 2026
Last updatedApril 13, 2026
Affected pluginoptimole-wp

What Changed in the Fix

Changes introduced in v4.2.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-5226 - Optimole Reflected XSS ## 1. Vulnerability Summary The **Optimole** plugin for WordPress (versions <= 4.2.3) contains a reflected cross-site scripting (XSS) vulnerability. The vulnerability resides in the **Page Profiler** feature. Specifically, the plu…

Show full research plan

Exploitation Research Plan: CVE-2026-5226 - Optimole Reflected XSS

1. Vulnerability Summary

The Optimole plugin for WordPress (versions <= 4.2.3) contains a reflected cross-site scripting (XSS) vulnerability. The vulnerability resides in the Page Profiler feature. Specifically, the plugin's get_current_url() function (likely within the OptimoleWP\PageProfiler\Profile class) retrieves the current request's URL path without sufficient sanitization. This unsanitized URL is then injected into a JavaScript block using a simple str_replace() call within the replace_content() function, rather than using proper JavaScript context escaping (like esc_js() or wp_json_encode()).

2. Attack Vector Analysis

  • Endpoint: Any frontend WordPress page.
  • Trigger: Appending the Page Profiler trigger parameter (likely ?optml_profile=1) to the URL.
  • Vulnerable Parameter: The URL path itself (Reflected via $_SERVER['REQUEST_URI']).
  • Authentication: None (Unauthenticated). The vulnerability is reachable by any visitor who can trigger the Page Profiler output.
  • Preconditions: The plugin must be active. The Page Profiler feature must be reachable (usually via query parameter).

3. Code Flow

  1. Initialization: Optml_Manager::instance() (in inc/manager.php) instantiates the OptimoleWP\PageProfiler\Profile class:
    self::$instance->page_profiler = new Profile();
    
  2. Hook Registration: The Profile class (likely in inc/page-profiler/profile.php, though file not provided) registers hooks to output the Page Profiler script (e.g., wp_footer or wp_enqueue_scripts).
  3. URL Retrieval: When the profiler is triggered (e.g., via ?optml_profile=1), the plugin calls get_current_url() to identify the page being profiled. This function typically returns $_SERVER['REQUEST_URI'].
  4. Insecure Injection: The replace_content() function contains a template JavaScript string with a placeholder. It uses str_replace() to swap the placeholder with the result of get_current_url():
    // Inferred logic in replace_content()
    $js_template = '<script>var optml_data = {"url":"{{URL_PLACEHOLDER}}"};</script>';
    $current_url = $this->get_current_url(); // Unescaped /path/";alert(1);//
    echo str_replace('{{URL_PLACEHOLDER}}', $current_url, $js_template);
    
  5. Execution: The browser renders the page, encounters the broken JavaScript string, and executes the injected script.

4. Nonce Acquisition Strategy

This is a Reflected XSS vulnerability via a GET request. Based on the vulnerability description and type:

  • No Nonce Required: The vulnerability triggers during the rendering of the page itself. Nonces are typically required for state-changing actions (POST/AJAX), but here the "action" is simply visiting a crafted URL.

5. Exploitation Strategy

We will use the http_request tool to perform a GET request to the WordPress site with a malicious URL path designed to break out of a JavaScript string.

Step-by-Step Plan:

  1. Construct Malicious URL:
    The payload needs to break out of a JSON-like object or variable assignment.

    • Context: {"url":"/index.php/[PAYLOAD]"}
    • Payload: ";alert(document.domain);var+dummy="
    • Full Path: /index.php/";alert(document.domain);var+dummy="/?optml_profile=1
  2. Send Request:
    Use http_request to visit the URL. We must ensure the path is sent exactly as intended.

    // Target URL construction
    const targetUrl = "http://localhost:8080/index.php/\";alert(document.domain);var+dummy=\"/?optml_profile=1";
    
  3. Analyze Response:
    Inspect the HTML source for the Page Profiler script block. Search for the string optml and verify if the alert payload exists unescaped within a <script> tag.

6. Test Data Setup

  1. Install Plugin: Ensure Optimole version 4.2.3 is installed and active.
  2. Permalinks: While not strictly required, having "Plain" permalinks (/index.php/path) or "Post name" permalinks helps in manipulating the path.
  3. Profiler Activation: No specific backend settings are required if the optml_profile=1 parameter is sufficient to trigger the code path.

7. Expected Results

A successful exploit will return an HTML response containing a script block similar to:

<script type="text/javascript">
    // ... other code ...
    var some_optimole_var = {"url":"/index.php/";alert(document.domain);var dummy="/?optml_profile=1"};
    // ...
</script>

The browser (if it were a real user) would execute alert(document.domain).

8. Verification Steps

  1. Search for Sink: In the response body from http_request, look for the <script> tag containing the Page Profiler data.
  2. Check Escaping: Confirm that the double quotes (") and semicolons (;) from the URL path are present verbatim in the response, proving that no JavaScript-context escaping was applied.
  3. Regex Match:
    grep -P "var.*optml.*\";alert\(document\.domain\)"
    

9. Alternative Approaches

If ?optml_profile=1 does not trigger the output:

  1. Check Authenticated State: Try triggering the profiler while logged in as an administrator (using browser_navigate and the agent's session). If it only triggers for admins, it is still a "Medium" severity Reflected XSS (Admin XSS).
  2. Vary URL Position: If the path injection is blocked by the web server (404/403), try injecting the payload into a query parameter if get_current_url() captures the full URL including query strings:
    • URL: http://localhost:8080/?optml_profile=1&dummy=";alert(1)//
  3. Check for different localization keys: Look for other JS variables like optimole_profiler_data or optmlProfiler in the source of inc/manager.php or inc/page-profiler/profile.php if accessible.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Optimole plugin for WordPress is vulnerable to Reflected Cross-Site Scripting (XSS) via the Page Profiler feature in versions up to 4.2.3. Unauthenticated attackers can inject arbitrary scripts into the page by crafting a malicious URL path that breaks out of a JavaScript variable assignment within the plugin's profiler script block.

Vulnerable Code

// inc/manager.php (lines 456-462 in version 4.2.3)
$hmac = wp_hash( $profile_id . $time . $this->get_current_url(), 'nonce' );
$js_optimizer = str_replace(
    [ Profile::PLACEHOLDER, Profile::PLACEHOLDER_MISSING, Profile::PLACEHOLDER_TIME, Profile::PLACEHOLDER_HMAC, Profile::PLACEHOLDER_URL ],
    [ $profile_id, implode( ',', $missing ), strval( $time ), $hmac, $this->get_current_url() ],
    $js_optimizer
);

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/optimole-wp/4.2.3/inc/manager.php	2026-03-25 10:54:40.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/optimole-wp/4.2.4/inc/manager.php	2026-04-03 08:34:00.000000000 +0000
@@ -453,10 +453,11 @@
 				if ( ! $this->page_profiler->exists_all( $profile_id ) ) {
 					$missing = $this->page_profiler->missing_devices( $profile_id );
 					$time = time();
-					$hmac = wp_hash( $profile_id . $time . $this->get_current_url(), 'nonce' );
+					$url  = esc_url( esc_js( $this->get_current_url() ) );
+					$hmac = wp_hash( $profile_id . $time . $url, 'nonce' );
 					$js_optimizer = str_replace(
 						[ Profile::PLACEHOLDER, Profile::PLACEHOLDER_MISSING, Profile::PLACEHOLDER_TIME, Profile::PLACEHOLDER_HMAC, Profile::PLACEHOLDER_URL ],
-						[ $profile_id, implode( ',', $missing ), strval( $time ), $hmac, $this->get_current_url() ],
+						[ $profile_id, implode( ',', $missing ), strval( $time ), $hmac, $url ],
 						$js_optimizer
 					);
 					$html = str_replace( Optml_Admin::get_optimizer_script( true ), $js_optimizer, $html );

Exploit Outline

The exploit targets the Page Profiler feature of the Optimole plugin. 1. Target Endpoint: Any public-facing page on the WordPress site. 2. Methodology: An attacker crafts a URL where the path contains a JavaScript breakout payload. Since the plugin uses the current URL (retrieved via `$_SERVER['REQUEST_URI']`) and reflects it inside a `<script>` tag using `str_replace` without proper escaping, the payload can terminate the existing string and execute arbitrary code. 3. Payload Shape: `/index.php/";alert(document.domain);var+dummy="/?optml_profile=1` 4. Authentication: No authentication is required (Unauthenticated Reflected XSS). The attacker simply needs to trick a logged-in user or an administrator into clicking the crafted link, or target any visitor to execute the script in their browser session.

Check if your site is affected.

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