SVG Map Plugin <= 1.0.0 - Cross-Site Request Forgery to Settings Update and Stored Cross-Site Scripting
Description
The SVG Map Plugin plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 1.0.0. This is due to missing or incorrect nonce validation on multiple AJAX actions including 'save_data', 'delete_data', and 'add_popup'. This makes it possible for unauthenticated attackers to update the plugin's settings, delete map data, and inject malicious web scripts via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:NTechnical Details
<=1.0.0# Exploitation Research Plan: CVE-2025-13519 (SVG Map Plugin) ## 1. Vulnerability Summary The **SVG Map by Smjrifle** plugin (versions up to 1.0.0) is vulnerable to Cross-Site Request Forgery (CSRF) leading to Stored Cross-Site Scripting (XSS). Multiple AJAX actions, specifically `save_data`, `dele…
Show full research plan
Exploitation Research Plan: CVE-2025-13519 (SVG Map Plugin)
1. Vulnerability Summary
The SVG Map by Smjrifle plugin (versions up to 1.0.0) is vulnerable to Cross-Site Request Forgery (CSRF) leading to Stored Cross-Site Scripting (XSS). Multiple AJAX actions, specifically save_data, delete_data, and add_popup, fail to implement proper nonce validation (or use incorrect validation logic). This allows an attacker to trick a logged-in administrator into making unintended requests that modify map settings, delete data, or inject malicious JavaScript into the map configuration.
2. Attack Vector Analysis
- Endpoints:
/wp-admin/admin-ajax.php - AJAX Actions:
save_data(Primary for XSS),delete_data,add_popup. - HTTP Method: POST
- Authentication: Requires a logged-in Administrator session (targeted via CSRF).
- Payload Parameter: Likely a JSON string or specific POST fields representing map data (e.g.,
data,content, orpopup_text). - Preconditions: An administrator must be tricked into visiting an attacker-controlled page while authenticated.
3. Code Flow (Inferred)
- Entry Point: The plugin registers AJAX handlers using
add_action('wp_ajax_save_data', ...)andadd_action('wp_ajax_add_popup', ...). - Missing Check: Inside the callback functions for these actions, there is either no call to
check_ajax_referer()orwp_verify_nonce(), or the check is incorrectly implemented (e.g., ignoring the return value). - Data Processing: The handler retrieves user input from
$_POST. - Database Sink: The input is stored in the database via
update_option()or$wpdb->insert()/update(). - Output (XSS): When the SVG map is rendered on the frontend or admin dashboard, the unsanitized input is printed directly into the HTML, executing the injected script.
4. Nonce Acquisition Strategy
The vulnerability description states "missing or incorrect nonce validation." If validation is truly missing, no nonce is required. However, if the agent needs to verify an "incorrect" implementation or if the plugin attempts to use a nonce but fails to verify it properly:
- Identify Script Localization: Search the source for
wp_localize_script. - Create Trigger Page: Create a page with the map shortcode (inferred to be
[svg-map]or similar based on plugin slug).wp post create --post_type=page --post_status=publish --post_title="Map Test" --post_content='[svg-map]' - Extract Nonce via Browser:
- Navigate to the created page using
browser_navigate. - Use
browser_evalto find potential nonce objects:// Inferred variable names based on common plugin patterns window.svg_map_obj?.nonce || window.smjrifle_map_data?.security
- Navigate to the created page using
- Source Check: If source is available, grep for the action used in
wp_create_nonceto ensure the correct string is used in the exploit.
5. Exploitation Strategy
We will target the save_data action to inject a Stored XSS payload via CSRF.
Step 1: Craft the CSRF Request
The request will be a POST to admin-ajax.php.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method: POST
- Headers:
Content-Type: application/x-www-form-urlencoded - Body:
(Note: The exact structure of theaction=save_data&data={"id":"1","title":"<script>alert(origin)</script>","other_params":"..."}dataparameter needs to be verified by looking at the plugin's JS or PHP handler.)
Step 2: Execute via Agent
Since the agent simulates the "attacker" and "victim" roles in an isolated environment, it can perform the request using the administrator's cookies directly to demonstrate the lack of CSRF protection.
// Using http_request tool
const response = await http_request({
url: "http://localhost:8080/wp-admin/admin-ajax.php",
method: "POST",
form: {
action: "save_data",
data: '{"title":"<script>alert(\'XSS\')</script>"}' // Payload
}
});
6. Test Data Setup
- Active Plugin: Ensure
svg-map-by-saediis installed and activated. - Create Map Instance: If the plugin requires an existing map ID, create one through the admin UI or via
wp eval. - Administrator User: Use the existing admin account to perform the authenticated request.
7. Expected Results
- HTTP Response: A successful JSON response (e.g.,
{"success":true}or1) despite no nonce being provided. - Database Change: The malicious
<script>tag is stored in the plugin's configuration options or database tables. - XSS Execution: Navigating to the page where the map is displayed triggers a JavaScript alert.
8. Verification Steps
- Check Database:
wp option get svg_map_data --format=json # OR if it uses a custom table wp db query "SELECT * FROM wp_svg_maps" - Frontend Check:
Navigate to the page containing the map and check for the presence of the payload:browser_eval("document.body.innerHTML.includes('<script>alert')")
9. Alternative Approaches
- Target
add_popup: Ifsave_datais well-sanitized, try theadd_popupaction. Popups often involve HTML content and are frequently overlooked during sanitization.- Payload:
action=add_popup&map_id=1&content=<img src=x onerror=alert(1)>
- Payload:
- Target
delete_data: To demonstrate CSRF without XSS, attempt to delete all map data by sending a request todelete_datawithout a nonce. Success confirms the CSRF vulnerability.
Summary
The SVG Map Plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) because it lacks nonce validation on multiple AJAX actions like 'save_data', 'delete_data', and 'add_popup'. This allows attackers to trick an administrator into executing unintended requests that can modify map settings, delete data, or inject malicious JavaScript (Stored XSS) into map configurations.
Vulnerable Code
// Inferred from plugin slug: svg-map-by-saedi add_action('wp_ajax_save_data', 'smjrifle_save_data_callback'); add_action('wp_ajax_add_popup', 'smjrifle_add_popup_callback'); add_action('wp_ajax_delete_data', 'smjrifle_delete_data_callback'); function smjrifle_save_data_callback() { // Vulnerability: No check_ajax_referer() or wp_verify_nonce() call if (isset($_POST['data'])) { $data = $_POST['data']; // Often processed as JSON or raw string update_option('svg_map_data', $data); echo json_encode(['success' => true]); } wp_die(); } --- function smjrifle_add_popup_callback() { // Vulnerability: No check_ajax_referer() or wp_verify_nonce() call global $wpdb; if (isset($_POST['content'])) { $content = $_POST['content']; // Unsanitized input leading to Stored XSS $wpdb->insert($wpdb->prefix . 'svg_map_popups', ['content' => $content]); } wp_die(); }
Security Fix
@@ -10,6 +10,7 @@ function smjrifle_save_data_callback() { + check_ajax_referer('svg_map_nonce_action', 'security'); if (isset($_POST['data'])) { - $data = $_POST['data']; + $data = sanitize_text_field($_POST['data']); update_option('svg_map_data', $data); @@ -20,6 +21,7 @@ function smjrifle_add_popup_callback() { + check_ajax_referer('svg_map_nonce_action', 'security'); global $wpdb; if (isset($_POST['content'])) { - $content = $_POST['content']; + $content = wp_kses_post($_POST['content']); $wpdb->insert($wpdb->prefix . 'svg_map_popups', ['content' => $content]);
Exploit Outline
The exploit targets the `/wp-admin/admin-ajax.php` endpoint via a CSRF attack. An attacker crafts a malicious HTML page containing a form that automatically submits a POST request to the target site. The payload includes the 'action' parameter set to 'save_data' or 'add_popup', and a 'data' or 'content' parameter containing a Stored XSS payload (e.g., <script>alert(1)</script>). Because the plugin does not verify a CSRF nonce, the request is processed using the authenticated session of a site administrator who views the attacker's page. Once stored, the malicious script executes whenever a user or admin views the affected map or popup in the WordPress dashboard or on the frontend.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.