
Prueba de concepto para XSS almacenado autenticado en Autoptimize < 3.1.14, aprovechando la sanitización insuficiente de atributos en la generación de etiquetas de precarga de imágenes.
Vulnerabilidad: Cross-Site Scripting (XSS) Almacenado Autenticado (Contributor+)
Versión Afectada: Autoptimize <= 3.1.13
Versión Parcheada: Autoptimize 3.1.14
Archivo: classes/autoptimizeImages.php
La vulnerabilidad existe en el método create_img_preload_tag() dentro de classes/autoptimizeImages.php. Esta función es responsable de generar etiquetas <link rel="preload"> para imágenes encontradas en el contenido cuando la optimización de imágenes o la precarga está habilitada.
En la versión 3.1.13, la función utiliza un enfoque de "lista negra" (mediante preg_replace) para eliminar atributos específicos como title, alt, , , y de la etiqueta `` original antes de convertirla en una etiqueta . Sin embargo, no elimina atributos de manejadores de eventos como o .
classidwidthheight<link>onloadonerrorUn atacante autenticado (con al menos rol de Contributor) puede incrustar una etiqueta `` maliciosa en una entrada. Cuando el plugin procesa esta entrada para generar enlaces de precarga, el manejador de eventos malicioso se conserva e inyecta en el <head> de la página dentro de una etiqueta <link>. Dado que <link rel="preload"> soporta el evento onload, el JavaScript se ejecuta cuando el recurso se carga.
// classes/autoptimizeImages.php
public static function create_img_preload_tag( $tag ) {
// ...
// rewrite img tag to link preload img.
$_from = array( '<img ', ' src="https://raw.githubusercontent.com/ciscocamelo/cve-2025-13401-xss-stored/main/," sizes=', ' srcset=' );
$_to = array( '<link rel="preload" as="image" ', ' href=', ' imagesizes=', ' imagesrcset=' );
$tag = str_replace( $_from, $_to, $tag );
// INSUFFICIENT SANITIZATION: Only removes specific attributes
$tag = preg_replace( '/ ((?:title|alt|class|id|loading|fetchpriority|decoding|data-no-lazy|width|height)=".*")/Um', '', $tag );
// ...
return $tag;
}
create_img_preload_tag se activa a menudo para imágenes detectadas en el viewport o precargadas explícitamente.<img src="https://example.com/image.jpg" onload="alert('XSS_POC_SUCCESS')">
<!-- Malicious Image -->
<img src="https://raw.githubusercontent.com/ciscocamelo/cve-2025-13401-xss-stored/main/wp-content/plugins/autoptimize/classes/external/js/lazysizes.min.js" onload="alert(document.cookie)">
<link rel="preload" as="image" href="/wp-content/plugins/autoptimize/classes/external/js/lazysizes.min.js" onload="alert(document.cookie)">
width, height, etc. pueden ser eliminados, pero onload permanece.<link>, precarga el recurso y dispara el evento onload, ejecutando el XSS.El parche reemplaza la regex de lista negra con wp_kses(), habilitando una estricta lista blanca de atributos permitidos para la etiqueta <link> generada.
// classes/autoptimizeImages.php v3.1.14
$allowed_html = array(
'link' => array(
'rel' => true,
'as' => true,
'href' => true,
'imagesizes' => true,
'imagesrcset' => true,
'type' => true,
'media' => true,
),
);
$tag = wp_kses( $tag, $allowed_html );