Limpiar HTML con expresiones regulares en WordPress sigue siendo una mala idea. Y cada cierto tiempo aparece un caso real que lo recuerda con datos sobre la mesa. El último análisis lo firma el investigador Stealthcopter, que ha vuelto a poner el foco en una clase de fallos que parecía folklore de la vieja escuela: una regex pensada para sanear atributos HTML termina rompiendo el marcado y abriendo la puerta a un XSS en toda regla.
El planteamiento es simple y por eso duele tanto. En lugar de eliminar un atributo concreto, la expresión regular salta dentro del valor de otro, se desplaza más de la cuenta y deja un HTML donde el texto controlado por el atacante se convierte en atributos nuevos. A veces basta para activar un onfocus, un onerror o un enlace con javascript: que se ejecuta en cuanto el navegador interpreta la página.
Y no hablamos de un escenario de laboratorio. Uno de los casos públicos citados afectó al plugin Schema & Structured Data for WP & AMP, donde una sustitución con preg_replace aplicada a comentarios de usuarios no autenticados desembocó en un Stored XSS. Sin login, sin permisos previos, sin tocar el panel: una entrada pública del sitio era suficiente para dejar el payload alojado.
Aquí hay un patrón que se repite. El código sanea bien al principio, el desarrollador da el contenido por seguro y, en una segunda pasada, mete una regex para quitar atributos como itemprop, itemscope o cualquier marca que no quiera ver en la salida. Esa segunda pasada es la que abre la grieta.
El motivo es directo: una expresión regular no entiende el árbol HTML, solo ve texto plano. No sabe dónde acaba un atributo, qué comillas pertenecen a qué, ni cuándo está cruzando la frontera entre dos etiquetas. Una sustitución que parece inofensiva puede borrar más de la cuenta y dejar un payload activo donde antes había un valor perfectamente válido.
En WordPress esto pesa especialmente porque durante años miles de plugins y snippets han tirado de preg_replace para retocar HTML. Ocupa tres líneas, parece rápido y soluciona la papeleta. Hasta que llega el primer comentario malicioso, el primer shortcode con UTF-8 raro o el primer campo personalizado que mete una comilla donde nadie esperaba. La mezcla es especialmente peligrosa cuando el contenido pasa por varios filtros antes de llegar a esa regex.
La buena parte de esta historia es que el core ya ofrece la pieza que toca. Desde hace varias versiones, WordPress incorpora WP_HTML_Tag_Processor, una clase pensada para recorrer etiquetas, leer atributos y eliminarlos sin tener que adivinar nada. Trabaja con la estructura real del documento, no con cadenas sueltas.
La diferencia se nota a la primera. Una llamada a remove_attribute( 'itemprop' ) o set_attribute( 'rel', 'noopener' ) es código autodocumentado y mucho más fácil de auditar que una cadena de preg_replace con cuantificadores raros y comillas escapadas. Si mañana cambia el formato del HTML de entrada, el procesador de etiquetas lo aguanta. Una regex frágil, no.
Para quien escribe plugins, la conclusión es clara: si tu código está limpiando HTML con regex en 2026, tienes deuda técnica acumulada y, posiblemente, una vulnerabilidad esperando a que alguien la encuentre. La migración a la API HTML del core no es opcional cuando el contenido viene de comentarios, formularios o cualquier campo abierto al usuario.
El detalle no es anecdótico. En los últimos meses se han ido encadenando avisos serios en plugins muy extendidos. Wordfence documentó ataques activos contra un addon de Elementor que permitía registro como administrador sin autenticación, y poco después se publicó la brecha de WooCommerce en la Store API que podía exponer pedidos de clientes invitados. Son fallos distintos, pero comparten ADN: código que parecía suficiente y que falló cuando se cruzó con un input inesperado.
El sitio típico de WordPress no se rompe por el core, sino por la suma de plugins, mu-plugins y snippets pegados en el functions.php a lo largo de los años. La cadena más débil suele ser una rutina rápida escrita para salir del paso. Y cuando ese código toca HTML, la posibilidad de un XSS deja de ser teórica.
Hay además un cambio de contexto importante. Con cada vez más bots de IA rastreando contenido, y con plugins como VigIA midiendo y frenando rastreadores, los HTML que sirven los sitios se procesan, indexan y vuelven a renderizar en muchos más sitios que antes. Un XSS antiguo en un plugin de schema puede acabar copiado en un fragmento citado por un asistente. La superficie ya no es solo el navegador del visitante.
Y aquí va la opinión sin maquillar. La explosión de asistentes de código está llenando los plugins de soluciones que parecen razonables a primera vista pero suspenden en cuanto el input se aparta del ejemplo limpio. Una regex para «quitar atributos peligrosos» es exactamente el tipo de respuesta que una IA propone con confianza cuando no tiene contexto de la API HTML moderna. Funciona en el snippet de prueba y revienta en producción.
Quien revisa código en agencias o quien mantiene plugins propios tendría que añadir una regla muy básica a la auditoría: si aparece preg_replace tocando HTML que viene del usuario, hay que mirarlo dos veces. Es el equivalente moderno a ver un eval con datos externos: no siempre es vulnerable, pero merece una segunda lectura.
En el plano operativo, las herramientas para auditar muchos sitios a la vez también se están moviendo. Proyectos como wp-malware-cleanup-mcp permiten escanear backdoors, administradores ocultos y patrones sospechosos en lote desde Claude Code, y eso ayuda a localizar restos de ataques previos. Pero el punto sigue siendo el mismo: hay que evitar que el código nuevo introduzca el problema, no solo limpiar lo que ya entró.
La traducción práctica del caso, sin paja, es esta:
preg_replace, preg_match o str_replace aplicados a HTML procedente de usuarios.WP_HTML_Tag_Processor o, en casos de sanitización general, a wp_kses con una whitelist explícita.El caso documentado por Stealthcopter cierra el círculo de un consejo viejo: no parsees HTML con regex. La frase tiene quince años en el mundo del desarrollo web, y en 2026 sigue siendo igual de válida. Solo que ahora hay más automatización, más código asistido por IA y menos paciencia para revisar lo que parece funcionar al primer vistazo.
¿Qué tipo de fallo se puede producir al usar regex sobre HTML en WordPress?
Aparece un XSS cuando la expresión regular elimina o reemplaza atributos de forma incorrecta y termina rompiendo el contexto del HTML. Parte del contenido del atacante se convierte en un atributo ejecutable, normalmente un manejador de evento como onfocus o onerror, o un enlace con javascript:.
¿Qué plugin se vio afectado por un caso público de este tipo?
El más comentado es Schema & Structured Data for WP & AMP, donde se documentó un Stored XSS no autenticado ligado a una sustitución con preg_replace sobre comentarios. El payload se podía dejar en una entrada pública sin pasar por el panel.
¿Qué alternativa recomienda WordPress frente a preg_replace() para modificar HTML?
La opción que pone el core encima de la mesa es WP_HTML_Tag_Processor. Recorre las etiquetas con su estructura real, permite leer y eliminar atributos concretos y no depende de patrones frágiles. Para sanitización general sigue siendo válido wp_kses con whitelist.
¿Esto afecta solo a plugins antiguos?
No. Puede aparecer en cualquier plugin, tema o snippet, incluso recientes, que siga usando regex para limpiar o reescribir HTML. El riesgo crece cuando el código toca contenido generado por usuarios: comentarios, formularios, campos personalizados, shortcodes o salidas filtradas en cadena.
¿Cómo detecto si mi sitio o un plugin que uso es vulnerable?
Busca en el código llamadas a preg_replace, preg_match o str_replace que reciban HTML procedente de $_POST, $_GET, comentarios, contenido de entradas o cualquier campo libre. Si la expresión intenta quitar etiquetas o atributos, márcalo para revisión y prueba con cadenas con comillas simples y dobles mezcladas, espacios extra y atributos sin valor.
¿La IA generativa empeora el problema o ayuda a resolverlo?
Depende del prompt. Sin contexto, los asistentes tienden a sugerir regex porque es la respuesta corta y aparente. Si pides explícitamente código con WP_HTML_Tag_Processor o wp_kses, la sugerencia suele ser correcta. La auditoría humana sigue siendo necesaria cuando el código toca entradas no confiables.
vía: REGEXSS
