WP Maps <= 4.9.4 - Authenticated (Admin+) Stored Cross-Site Scripting via 'location_messages' Parameter
Description
The WP Maps – Google Maps,OpenStreetMap,Mapbox,Store Locator,Listing,Directory & Filters plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'location_messages' parameter in all versions up to, and including, 4.9.4 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with administrator-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page. Exploitation requires the attacker to hold the custom wpgmp_manage_location capability, which is granted to administrators by default but can be assigned to lower-privileged roles via the plugin's Permissions screen.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=4.9.4What Changed in the Fix
Changes introduced in v4.9.5
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-9594 (WP Maps Stored XSS) ## 1. Vulnerability Summary The **WP Maps** plugin (up to 4.9.4) is vulnerable to **Stored Cross-Site Scripting (XSS)** via the `location_messages` parameter. The vulnerability exists in the `WPGMP_Model_Location` class within `module…
Show full research plan
Exploitation Research Plan: CVE-2026-9594 (WP Maps Stored XSS)
1. Vulnerability Summary
The WP Maps plugin (up to 4.9.4) is vulnerable to Stored Cross-Site Scripting (XSS) via the location_messages parameter. The vulnerability exists in the WPGMP_Model_Location class within modules/location/model.location.php. Specifically, the write_to_db_backup() method accepts the location_messages POST parameter and saves it to the database using only wp_unslash(), omitting any sanitization (e.g., wp_kses or sanitize_text_field). When these locations are retrieved for display (e.g., on a map), the unsanitized content is rendered, allowing execution of arbitrary JavaScript in the context of any user viewing the map.
2. Attack Vector Analysis
- Endpoint: Admin form submission (typically
admin.php?page=wpgmp_form_locationor a related AJAX action). - Vulnerable Parameter:
location_messages - Authentication: Required. An attacker must have the
wpgmp_manage_locationcapability (granted to Administrators by default). - Preconditions: The plugin must be active, and at least one map must be created to display the malicious location.
3. Code Flow
- Entry Point: An authenticated user submits a request to add or edit a location. This triggers the saving logic, likely calling
WPGMP_Model_Location::write_to_db_backup(). - Storage (Sink): In
modules/location/model.location.php,write_to_db_backup()takes$_POST['location_messages']:
The data is then stored in theif ( isset( $_POST['location_messages'] ) ) $data['location_messages'] = wp_unslash( $_POST['location_messages'] );{$wpdb->prefix}map_locationstable viaFlipperCode_Database::insert_or_update. - Processing: When a map is rendered via shortcode,
modules/shortcode/views/put-wpgmp.phpcalls$location_obj->fetch(). - Transformation: In
fetch(), the plugin attempts to decodelocation_messages:
Ifif ( ! is_null( $object->location_messages ) ) { $decoded = base64_decode( $object->location_messages ); $parsed = maybe_serialize( $decoded ); // Note: possible typo in source, likely intended maybe_unserialize if ( is_array( $parsed ) && isset( $parsed['googlemap_infowindow_message_one'] ) ) { $object->location_messages = $parsed['googlemap_infowindow_message_one']; } }base64_decodefails or the result isn't a serialized array, the original payload persists. - Output (Sink): The fetched locations are passed to the frontend JavaScript (Leaflet/Google Maps), which renders the
location_messagesinside an InfoWindow without proper output escaping.
4. Nonce Acquisition Strategy
The plugin uses nonces for admin operations. The update_loc function in modules/location/model.location.php explicitly checks for wpgmp-nonce.
Steps to obtain the nonce:
- Identify the shortcode: Use
[put_wpgmp id='1']. - Create a page with the shortcode using WP-CLI.
- Navigate to the Admin Location page:
/wp-admin/admin.php?page=wpgmp_form_location. - Use
browser_evalto extract the nonce from the localized script. The plugin typically localizes data under a global object. - Target JS Variable:
window.wpgmp_local?.nonceor similar. Check the page source forwp_localize_scriptcalls associated withwpgmp-nonce.
5. Exploitation Strategy
The goal is to inject an XSS payload into the location_messages field.
Step 1: Data Setup
Create a Map and a Location to identify the correct entityID and map_id.
# Create a map
wp eval "new WPGMP_Model_Map();" # Simplified: Usually done via UI
Step 2: Payload Delivery
Use http_request to send a POST request to the location save handler.
Request Details:
- URL:
http://localhost:8080/wp-admin/admin.php?page=wpgmp_form_location(or the AJAX handler if confirmed) - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
_wpnonce: [EXTRACTED_NONCE]location_title:XSS Testlocation_address:123 Test Stlocation_messages:<script>alert(document.domain)</script>location_settings[extensions_fields]:...page:wpgmp_form_locationaction:wpgmp_save_location(Inferred from model class methods)
Note: If the base64_decode in fetch() interferes, the payload should be a base64-encoded serialized array:location_messages = YToxOntzOjMyOiJnb29nbGVtYXBfaW5mb3dpbmRvd19tZXNzYWdlX29uZSI7czoyNToiPHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0PiI7fQ==
Step 3: Triggering the XSS
Navigate to the page containing the [put_wpgmp] shortcode. The payload will execute when the location's InfoWindow is triggered or the map loads.
6. Test Data Setup
- Plugin: Install and activate
wp-google-map-pluginv4.9.4. - User: Create an admin user to perform the injection.
- Map: Create a map with ID
1. - Shortcode Page:
wp post create --post_type=page --post_title="Map Page" --post_status=publish --post_content="[put_wpgmp id='1']"
7. Expected Results
- The POST request should return a success message (e.g., "Location added successfully").
- When viewing the "Map Page", the browser should execute the injected script (e.g., show an alert box).
8. Verification Steps
After the HTTP request, verify the database entry via WP-CLI:
wp db query "SELECT location_messages FROM wp_map_locations ORDER BY location_id DESC LIMIT 1;"
Confirm the output contains the raw <script> tag or the crafted base64 string.
9. Alternative Approaches
If the direct POST to the admin page fails, check for an AJAX entry point:
- Action:
wp_ajax_wpgmp_save_location - Endpoint:
/wp-admin/admin-ajax.php - Parameter:
fc-location-new-set(observed inupdate_loc()as a JSON string). This method might require injecting into the JSON object properties likemessages.
Summary
The WP Maps plugin (up to 4.9.4) is vulnerable to Stored Cross-Site Scripting (XSS) via the 'location_messages' parameter. Authenticated attackers with the 'wpgmp_manage_location' capability (administrators by default) can inject arbitrary web scripts that execute in the context of any user viewing a map containing the malicious location.
Vulnerable Code
// modules/location/model.location.php public function write_to_db_backup(){ $entityID = ''; if ( isset( $_POST['entityID'] ) ) $entityID = intval( wp_unslash( $_POST['entityID'] ) ); if ( isset( $_POST['location_messages'] ) ) $data['location_messages'] = wp_unslash( $_POST['location_messages'] );
Security Fix
@@ -187,2 +187,2 @@ if ( isset( $_POST['location_messages'] ) ) - $data['location_messages'] = wp_unslash( $_POST['location_messages'] ); + $data['location_messages'] = wp_kses_post( wp_unslash( $_POST['location_messages'] ) );
Exploit Outline
1. Authenticate with Administrator privileges (or a role with the 'wpgmp_manage_location' capability). 2. Navigate to the map location management screen and extract the 'wpgmp-nonce' from the page source or localized script variables. 3. Send a POST request to '/wp-admin/admin.php?page=wpgmp_form_location' with the 'location_messages' parameter containing a JavaScript payload (e.g., <script>alert(1)</script>). 4. Ensure the request includes required fields: '_wpnonce', 'location_title', and 'location_address'. 5. Navigate to a frontend page containing the '[put_wpgmp]' shortcode that displays the affected map. The script will execute when the map loads or when the location's InfoWindow is opened.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.