Skip to content

Todo para WordPress, el desarrollo web — y mucho más

💡 Cross-site scripting (XSS): qué es y cómo proteger tu sitio en 2026

💡 Cross-site scripting (XSS): qué es y cómo proteger tu sitio en 2026

En 2019, casi el 75% de las grandes empresas sufrieron cross-site scripting. Siete años después, el XSS sigue aquí. Microsoft reportó 970 casos de XSS cerrados solo desde enero de 2024, y una vulnerabilidad en 2025 en el plugin LiteSpeed Cache puso en riesgo 7 millones de sitios WordPress.

El problema no es la tecnología. JavaScript, el lenguaje de la web interactiva, impulsa cada tema, cada formulario de comentarios, cada carrito de compras. El problema es que un atacante puede forzar a su sitio a ejecutar su código, y el navegador no puede distinguir un script malicioso de uno legítimo.

Analicemos la mecánica del XSS, tres tipos de ataques y las capas específicas de protección que blindan su sitio contra el cross-site scripting. Con herramientas, ejemplos de código y casos reales de WordPress.

💡 Resumen rápido:

  • Qué es el XSS y cómo un atacante inyecta código malicioso en un sitio de confianza
  • Tres tipos de cross-site scripting (almacenado, reflejado y basado en DOM) y en qué se diferencian
  • Configuración paso a paso de tres capas de protección: WAF, escape de salida y Política de Seguridad de Contenido
  • Dónde buscar vulnerabilidades XSS en su sitio y qué hacer si ya ocurrió un ataque

Qué es el cross-site scripting

Diagrama de ataque de cross-site scripting en un sitio web

Cross-Site Scripting es un ataque de inyección en el que un atacante incrusta un script malicioso en una página de un sitio de confianza. El navegador de la víctima ejecuta este código porque lo trata como parte de la página legítima. De ahí el nombre: el script llega «cruzando el límite del sitio».

Técnicamente, el vector de ataque no se limita a JavaScript. Existen vulnerabilidades posibles en HTML, Flash, ActiveX y CSS. Pero en la práctica, la gran mayoría de los exploits apuntan a JS. La razón: el acceso al árbol DOM, las cookies, el localStorage y la capacidad de realizar solicitudes en nombre del usuario.

En WordPress, las vulnerabilidades casi siempre surgen a través de plugins y temas que manejan incorrectamente la entrada del usuario. Formularios de comentarios, barras de búsqueda, formularios de contacto, páginas de inicio de sesión: cualquier campo que acepte datos y los devuelva sin filtrar se convierte en un punto de entrada. Según Claranet, se encontraron 2570 casos de XSS reflejado y almacenado en aplicaciones web probadas en 2024.

Cómo funciona el XSS

Un atacante necesita dos condiciones: un punto de entrada para el código malicioso y la ausencia de filtrado en la salida. En la práctica, esto se logra de dos maneras: mediante la manipulación de la entrada del usuario y mediante la evasión de la política del mismo origen.

Inyección a través de la entrada del usuario

El escenario más común. Un campo de usuario (barra de búsqueda, formulario de comentarios, campo de carga de archivos) acepta no solo texto, sino código ejecutable. Si el plugin o el tema no escapan la salida, un <script>alert('XSS')</script> ingresado se ejecutará en el navegador de todos los que abran la página.

El problema es más profundo de lo que parece. Incluso desarrolladores experimentados pasan por alto vectores XSS a través de campos aparentemente inofensivos: cargar un archivo SVG con un script incrustado, ingresar datos en el campo «nombre de usuario» durante el registro, parámetros de URL en redirecciones. Un campo sin esc_url() o esc_attr(), y el sitio queda expuesto.

En un mundo ideal, un campo de búsqueda acepta texto plano y nada más. En el ecosistema real de WordPress con más de 60 000 plugins, esta garantía es inalcanzable: basta con un plugin que tenga echo $_GET['q'] sin esc_html().

Evasión de la política del mismo origen

Ilustración de cómo eludir la política del mismo origen del navegador

La política del mismo origen es una regla de seguridad fundamental del navegador: los scripts de un origen no pueden leer datos de otro. Una página de Facebook y una página bancaria abiertas en el mismo navegador no intercambian información. Pero esta regla tiene un talón de Aquiles: las cookies de sesión.

Cuando usted inicia sesión en un sitio, el navegador crea una cookie de sesión que confirma su identidad con cada solicitud. Sin ella, tendría que ingresar su contraseña al navegar a cada nueva página. El problema es que el navegador adjunta esta cookie a cualquier solicitud al dominio, incluidas las solicitudes iniciadas por un script malicioso.

Esquema del ataque: un atacante encuentra una vulnerabilidad XSS en example.com → inyecta un script que lee document.cookie → envía la cookie de sesión a su servidor. Resultado: acceso completo a la cuenta de la víctima sin conocer la contraseña. Las cookies de sesión almacenan credenciales, contenido del carrito, información de envío: todo el contexto del usuario.

Tres tipos de ataques XSS

Captura de pantalla del juego educativo Google XSS Game para encontrar vulnerabilidades

La clasificación de XSS se basa en dónde y cómo el código malicioso llega a la víctima. Existen tres tipos, y proteger su sitio requiere comprender la mecánica de cada uno.

XSS almacenado (tipo I)

El tipo más peligroso. El script malicioso se guarda en el servidor (en la base de datos, en logs, en un campo de comentario) y se ejecuta cada vez que se abre la página infectada. En WordPress, este es un escenario clásico: un atacante deja un comentario con una etiqueta <script>, el plugin de comentarios no filtra el HTML y el script se dispara para cada visitante de la entrada.

La particularidad del XSS almacenado es que el ataque no necesita activarse mediante un enlace de phishing. La víctima simplemente visita la página. En 2025, la vulnerabilidad CVE-2025-12709 en el plugin Interactions para WordPress fue un caso clásico de XSS almacenado debido a una sanitización insuficiente de la entrada en los selectores de eventos.

XSS reflejado (tipo II)

El atacante envía a la víctima un enlace que contiene código malicioso en los parámetros de la URL. El servidor «refleja» este código de vuelta en la respuesta, por ejemplo, en un mensaje de error de búsqueda o en una línea «Usted buscó: X». El navegador ejecuta el script porque llegó en el cuerpo de la respuesta desde un servidor de confianza.

El XSS reflejado requiere una acción activa de la víctima: hacer clic en un enlace. Por lo tanto, el ataque suele disfrazarse como una URL legítima en un correo de phishing. En WordPress, un vector típico son los plugins de búsqueda que muestran la consulta de búsqueda sin esc_html().

XSS basado en DOM (tipo 0)

A diferencia de los dos primeros, aquí la vulnerabilidad no está en el código del lado del servidor, sino en el JavaScript del lado del cliente. Los datos maliciosos nunca llegan al servidor; se procesan directamente en el navegador a través de métodos inseguros de la API del DOM como innerHTML, document.write() o eval().

La fuente de datos es la URL (a través de window.location), document.referrer o cualquier otra fuente controlable en el cliente. Los logs del servidor están limpios; el ataque solo es visible en el navegador. Este XSS es el más difícil de detectar porque los WAF y los escáneres del lado del servidor no lo ven.

Por qué XSS es especialmente peligroso para WordPress

WordPress es el objetivo número uno para XSS por una razón: el ecosistema. De los más de 60 000 plugins en el repositorio, no todos pasan por una revisión estricta del escapado de salida. Un solo plugin con una vulnerabilidad compromete todo el sitio.

En septiembre de 2025, Microsoft publicó un análisis de por qué XSS sigue siendo una amenaza 25 años después de su aparición. La conclusión clave: la complejidad de la pila web moderna hace que la eliminación completa del XSS sea casi imposible, demasiadas capas donde se puede omitir el escapado.

Lo que un atacante obtiene mediante XSS en WordPress:

  • Acceso al panel de administración mediante el robo de cookies de sesión del administrador
  • Inyección de enlaces ocultos (spam SEO)
  • Descarga de malware en los equipos de los visitantes
  • Sustitución de los datos de pago en WooCommerce
  • Defacement masivo de páginas del sitio

Combinado con ingeniería social, el XSS se convierte en un vector para ataques sofisticados: desde la instalación de keyloggers hasta la falsificación de solicitudes entre sitios.

Cómo proteger su sitio contra XSS: tres capas

Tres capas de protección de WordPress contra cross-site scripting

La protección contra XSS no se resuelve con una sola configuración. Solo funciona la defensa en profundidad: los plugins de seguridad bloquean los ataques burdos, el escapado de salida cierra los vectores técnicos y la Política de Seguridad del Contenido bloquea la ejecución de scripts a nivel del navegador.

Capa 1: plugins de seguridad y firewall

La primera línea de defensa es un plugin de WordPress con un Firewall de Aplicaciones Web (WAF). El WAF filtra las peticiones entrantes antes de que lleguen al código del plugin y bloquea las firmas conocidas de ataques XSS.

Al elegir un plugin de seguridad, utilice esta lista de comprobación:

  • Escaneo regular de malware y CVEs conocidos en los plugins instalados
  • Firewall con reglas para bloquear patrones XSS en las peticiones
  • Endurecimiento de WordPress: desactivar XML-RPC, cambiar el prefijo de las tablas, impedir la edición de archivos desde el administrador
  • Gestión centralizada de actualizaciones para todos los plugins y temas
  • Copia de seguridad, para poder restaurar el sitio si un ataque logra traspasar las defensas

Puede encontrar una selección de plugins de seguridad para WordPress con desgloses detallados de las características de cada herramienta en revisiones especializadas de nuestro sitio.

Capa 2: validación y escapado de salida

Esta es la principal línea de defensa técnica. La regla es simple e innegociable: ningún dato de usuario se envía al navegador sin escapado. WordPress proporciona funciones integradas para esto, y cada una está vinculada a un contexto de salida específico.

Kit de herramientas básico para desarrolladores de WordPress:

1// For output inside HTML tags — between <p> and </p>
2echo esc_html($user_input);
3
4// For HTML attributes — inside value="..."
5echo esc_attr($user_input);
6
7// For URLs in href, src, and other attributes
8echo esc_url($user_url);
9
10// For output inside <textarea>
11echo esc_textarea($user_text);
12
13// For JavaScript variables
14echo esc_js($user_data);
15
16// For allowed HTML tags with dangerous attributes removed
17echo wp_kses_post($user_html);

El punto clave: la elección de la función depende del contexto. esc_html() en un atributo href no le salvará; el atacante insertará javascript:alert('XSS'). A la inversa, esc_url() dentro de un párrafo dejará pasar una etiqueta <script>. El contexto determina la función.

wp_kses() merece una mención especial: un filtro potente que solo permite etiquetas y atributos HTML autorizados. Para el contenido de usuario (comentarios, descripciones de perfil, campos personalizados), este es el nivel mínimo de filtrado requerido.

Capa 3: Política de Seguridad del Contenido (CSP)

CSP es una cabecera HTTP que le dice al navegador: «Ejecute scripts solo desde estas fuentes». Esta es la última línea de defensa. Incluso si un atacante inyectó un <script> en la página, el navegador no lo ejecutará porque los scripts en línea no están en la lista blanca.

Política CSP básica para WordPress:

1// In functions.php or via a plugin
2function add_csp_header() {
3 header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;");
4}
5add_action('send_headers', 'add_csp_header');

Una política estricta ('strict-dynamic' en lugar de 'unsafe-inline') es más segura pero requiere configurar nonce o hashes para cada script legítimo. Esto supone un trabajo considerable en un sitio con una docena de plugins activos. Comience con el modo solo informe para recopilar registros de violaciones sin romper el frontend:

1Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint

CSP no reemplaza el escapado. Mitiga las consecuencias de los errores cuando el escapado se omitió en algún lugar.

Vídeo: XSS desde lo básico hasta la explotación

Para ver XSS en acción y entender cómo encontrar vulnerabilidades en sitios reales, vea este desglose de 30 minutos:

Después de verlo, vuelva a las capas de protección anteriores. Ahora tendrán sentido a nivel mecánico, no solo a nivel de nombres de funciones.

⁉️🤔 Preguntas frecuentes

¿Actualizar WordPress y los plugins ayudará a protegerse contra XSS?

Sí, y este es el paso de protección más subestimado. Cada nueva versión de un plugin a menudo cierra CVEs específicos, incluidas vulnerabilidades XSS. La vulnerabilidad de LiteSpeed Cache CVE-2025-12450 fue parcheada una semana después de su descubrimiento, pero 7 millones de sitios que no se actualizaron permanecieron expuestos. Active las actualizaciones automáticas para todos los plugins; los problemas de compatibilidad son raros, mientras que un parche omitido le golpea con seguridad.

¿Es suficiente un plugin de seguridad para protegerse contra XSS?

No. Un plugin de seguridad con WAF cierra las firmas de ataque conocidas pero no detecta vulnerabilidades de día cero ni vectores no estándar. Debe ser la primera capa, seguida del escapado de salida en el código del tema y las cabeceras CSP. Las tres capas juntas proporcionan una protección que ninguna de ellas puede ofrecer por sí sola.

¿Cómo verifico si mi sitio tiene vulnerabilidades XSS?

Comience con un escáner gratuito: WPScan, Sucuri SiteCheck, Qualys SSL Labs. Para pruebas más profundas, ejecute OWASP ZAP (Zed Attack Proxy), una herramienta de código abierto que automáticamente aplica fuzzing a los campos de entrada y detecta XSS reflejado. Importante: los escáneres automatizados no ven el XSS basado en DOM; eso requiere una auditoría manual del código JavaScript del sitio.

¿Se puede eliminar completamente el XSS en un sitio grande?

La eliminación completa del XSS en un sitio con docenas de plugins y un tema personalizado es una tarea cercana al ideal pero difícil de alcanzar por completo. Cada nuevo plugin, cada actualización de tema, cada fragmento personalizado en functions.php es un punto de entrada potencial. Un objetivo realista: tres capas de protección, actualizaciones automáticas, auditorías trimestrales y CSP en modo solo informe. De esta manera detectará la gran mayoría de los ataques en una etapa temprana.

¿Qué debo hacer si mi sitio ya ha sido atacado mediante XSS?

Cambie inmediatamente todas las contraseñas y restablezca las claves de sesión en wp-config.php usando el generador de WordPress. Luego restaure el sitio desde una copia de seguridad limpia. Después de la restauración, instale un plugin de seguridad, actualice todos los plugins y temas a las últimas versiones y añada una cabecera CSP en functions.php. Las contraseñas deben cambiarse porque el XSS a menudo roba las cookies de sesión del administrador.

¿Son lo mismo XSS e inyección SQL?

No, aunque ambos son ataques de inyección. La inyección SQL apunta a la base de datos a través de una consulta SQL; el atacante puede leer, modificar o eliminar tablas. El XSS apunta al navegador del usuario a través de JavaScript; el objetivo es robar sesiones, mostrar formularios de phishing o alterar el contenido de la página. Tienen vectores diferentes, funciones de protección diferentes ($wpdb->prepare() para SQL, esc_html() para XSS) y consecuencias diferentes. Pero en la práctica, a menudo se presentan juntos: el XSS se utiliza para realizar inyección SQL a través del panel de administración.

¿Debería temer al XSS en 2026?

El XSS no ha desaparecido, pero defenderse contra él se ha convertido en una rutina de ingeniería, no en magia. Tres capas (un plugin con WAF, escapado de salida en todos los puntos de contacto con el usuario y una cabecera CSP) cierran la gran mayoría de los vectores. Además de las actualizaciones automáticas de plugins y temas, para que los parches lleguen antes que los exploits.

Si actualmente no está utilizando ninguna de estas capas, comience por instalar un plugin de seguridad y activar las actualizaciones automáticas en el administrador de WordPress. Esto lleva 10 minutos y cierra los puntos de entrada más burdos. Luego vuelva a este artículo cuando esté listo para implementar el escapado y CSP.