CVE-2026-9060

Store Locator WordPress < 1.6.6 - Authenticated (Administrator+) Stored Cross-Site Scripting

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

Description

The Store Locator WordPress plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to 1.6.6 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. This only affects multi-site installations and installations where unfiltered_html has been disabled.

CVSS Vector Breakdown

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

Technical Details

Affected versions<1.6.6
PublishedJune 11, 2026
Last updatedJune 15, 2026
Affected pluginagile-store-locator

What Changed in the Fix

Changes introduced in v1.6.6

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-9060 ## 1. Vulnerability Summary The **Store Locator WordPress (agile-store-locator)** plugin is vulnerable to **Authenticated Stored Cross-Site Scripting (XSS)** in versions up to 1.6.6. The vulnerability exists in the `save_setting` method within `includes/…

Show full research plan

Exploitation Research Plan - CVE-2026-9060

1. Vulnerability Summary

The Store Locator WordPress (agile-store-locator) plugin is vulnerable to Authenticated Stored Cross-Site Scripting (XSS) in versions up to 1.6.6. The vulnerability exists in the save_setting method within includes/admin/setting.php, which handles the saving of plugin configurations.

User input from $_POST['data'] and $_POST['map_style'] is processed using stripslashes_deep or stripslashes but is not passed through WordPress sanitization functions (like sanitize_text_field or wp_kses). These values are stored directly in the database (asl_configs table and asl_settings table). When these settings are later retrieved and rendered on the frontend (via wp_localize_script or direct output in templates), the injected scripts execute.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: asl_save_setting (Inferred from the method name save_setting in Setting class)
  • Vulnerable Parameters:
    • map_style: Stored and rendered as part of the Google Maps initialization.
    • data[api_key]: Stored and rendered in admin and frontend contexts.
    • slug_attr_ddl: Processed via Helper::set_setting.
  • Authentication Level: Administrator (or users with the administrator capability as defined by the ASL_PERMISSION constant).
  • Preconditions:
    • The attacker must have Administrator-level access.
    • The vulnerability is particularly relevant in Multisite environments or environments where unfiltered_html has been disabled for Administrators.

3. Code Flow

  1. Entry Point: An authenticated administrator sends a POST request to admin-ajax.php with the action asl_save_setting.
  2. Processing: The request is routed to AgileStoreLocator\Admin\Setting::save_setting().
  3. Sink (Input):
    • In includes/admin/setting.php, the function retrieves $_POST['data'] and $_POST['map_style'].
    • It uses stripslashes_deep($_POST['data']) and stripslashes($_POST['map_style']).
    • It performs a loop: foreach ($keys as $key) { $wpdb->update(ASL_PREFIX . 'configs', ['value' => $data_[$key]], ['key' => $key]); }.
    • It calls \AgileStoreLocator\Helper::set_setting(...) for map_style.
  4. Storage: The unsanitized payload is stored in the wp_asl_configs table (or similar prefix).
  5. Output (Frontend):
    • includes/frontend/app.php calls get_public_config(), which executes SELECT * FROM ... ASL_PREFIX configs.
    • The configuration is passed to the frontend via wp_localize_script under the object name asl_configs.
    • Alternatively, map_style may be rendered raw within a <script> block to initialize the map.

4. Nonce Acquisition Strategy

The plugin uses the asl_admin_conf JavaScript object to store configuration data and nonces in the admin interface.

  1. Navigate: Move the browser to the Store Locator settings page: /wp-admin/admin.php?page=asl-settings.
  2. Extract: Use browser_eval to retrieve the nonce from the localized script:
    window.asl_admin_conf?.asl_nonce
    
  3. Action String: The nonce is likely generated with the action asl_nonce or similar, used to authorize the asl_save_setting AJAX call.

5. Exploitation Strategy

Step 1: Authentication and Nonce Extraction

  • Authenticate as an Administrator.
  • Navigate to /wp-admin/admin.php?page=asl-settings.
  • Execute browser_eval("asl_admin_conf.asl_nonce") to get the nonce.

Step 2: Inject Stored XSS Payload

  • Method: POST
  • URL: http://[target]/wp-admin/admin-ajax.php
  • Content-Type: application/x-www-form-urlencoded
  • Payload (injecting into map_style):
    action=asl_save_setting
    &asl_nonce=[EXTRACTED_NONCE]
    &map_style=[]});alert(document.domain);//
    &data[api_key]=AIzaSy... (a valid-looking key)
    &data[default_lat]=0
    &data[default_lng]=0
    
    Note: The map_style is often injected into a JS object. The ]}); part of the payload is designed to break out of the JSON/Array structure in the resulting frontend script.

Step 3: Trigger Execution

  • Create or view a page containing the shortcode [ASL_STORELOCATOR].
  • The script will execute when the Google Map attempts to load the custom style.

6. Test Data Setup

  1. Install and activate Agile Store Locator version 1.6.5.
  2. Create a WordPress Page with the following content:
    [ASL_STORELOCATOR]
    
  3. Ensure the user used for the exploit has the administrator role.
  4. (Optional) If testing for the unfiltered_html bypass specifically, define define( 'DISALLOW_UNFILTERED_HTML', true ); in wp-config.php.

7. Expected Results

  • The admin-ajax.php response should return {"success":true,"msg":"Setting has been updated successfully."}.
  • When visiting the page with the [ASL_STORELOCATOR] shortcode, a JavaScript alert(document.domain) (or similar payload) should trigger.
  • Checking the database will show the payload in the value column of the asl_configs table where key = 'map_style'.

8. Verification Steps

  1. Verify Storage via WP-CLI:
    wp db query "SELECT value FROM wp_asl_configs WHERE \`key\` = 'map_style';"
    
    Check if the output contains the raw <script> or breakout payload.
  2. Verify Frontend Render:
    Use http_request to fetch the frontend page and grep for the payload:
    # Search for the breakout in the localized JS
    grep "alert(document.domain)" 
    

9. Alternative Approaches

If map_style is not rendered directly, target data[api_key]:

  • Inject <img src=x onerror=alert(1)> into data[api_key].
  • Check the Admin Settings page itself (/wp-admin/admin.php?page=asl-settings). If the api_key input field value is rendered as <input value="<img src=x onerror=alert(1)>" ...>, the XSS will trigger in the admin context when the administrator revisits the settings page.

Check if your site is affected.

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