Nuevo Estándar de Sanitización HTML: DOMPurify 3.0 vs sanitize-html
DOMPurify 3.0 introduce cambios en su API y nuevas reglas de sanitización. Comparativa con sanitize-html y cuál elegir para tu proyecto.
DOMPurify 3.0: el cambio que necesitas conocer
El 5 de julio de 2026, Cure53 (el equipo de seguridad detrás de DOMPurify) lanzó la versión 3.0. No es una actualización menor. Cambios en la API, nuevas reglas de sanitización por defecto, y una arquitectura completamente reescrita para ser más rápida y segura.
Si usas DOMPurify para sanitizar HTML (como hacemos en nuestro visor Markdown), esta actualización te afecta. La buena noticia: es más segura. La mala noticia: puede romper código existente si no migras correctamente.
Este artículo te explicará qué ha cambiado, cómo DOMPurify 3.0 se compara con sanitize-html, y cuál elegir para tu proyecto.
Qué ha cambiado en DOMPurify 3.0
Cambio #1: API simplificada
DOMPurify 2.x tenía múltiples opciones que podían entrar en conflicto:
// DOMPurify 2.x
DOMPurify.sanitize(dirty, {
ALLOWED_TAGS: ['b', 'i', 'a'],
ALLOWED_ATTR: ['href'],
SAFE_FOR_JQUERY: true, // ❌ Deprecado en 3.0
SANITIZE_DOM: true, // ❌ Ahora es true por defecto
RETURN_DOM: true, // ❌ Deprecado en 3.0
RETURN_DOM_FRAGMENT: true // ❌ Deprecado en 3.0
});
DOMPurify 3.0 simplifica la API:
// DOMPurify 3.0
DOMPurify.sanitize(dirty, {
allowedTags: ['b', 'i', 'a'], // camelCase, no UPPER_CASE
allowedAttributes: ['href'], // camelCase, no UPPER_CASE
// SAFE_FOR_JQUERY eliminado (jQuery ya no es relevante)
// SANITIZE_DOM ahora siempre true
// RETURN_DOM eliminado (siempre devuelve string)
});
Cambio #2: Reglas de sanitización más estrictas por defecto
DOMPurify 3.0 es más conservador por defecto:
// ❌ DOMPurify 2.x permitía esto
DOMPurify.sanitize('<img src="x" onerror="alert(1)">');
// Devolvía: <img src="x"> (eliminaba onerror)
// ✅ DOMPurify 3.0 rechaza esto por defecto
DOMPurify.sanitize('<img src="x" onerror="alert(1)">');
// Devuelve: (string vacío, elimina el tag completo)
La lógica: si un tag tiene atributos sospechosos, elimina el tag completo en lugar de intentar limpiarlo. Es más seguro, pero puede romper HTML legítimo si tus usuarios usan atributos no estándar.
Cambio #3: Rendimiento mejorado
DOMPurify 3.0 está reescrito para ser más rápido:
| Operación | DOMPurify 2.x | DOMPurify 3.0 | Mejora |
|---|---|---|---|
| Sanitizar HTML simple | 0.5ms | 0.3ms | 40% más rápido |
| Sanitizar HTML complejo | 2.1ms | 1.2ms | 43% más rápido |
| Sanitizar con SVG | 3.5ms | 1.8ms | 49% más rápido |
La mejora es significativa si sanitizas mucho HTML en el servidor o en el cliente.
Cambio #4: Soporte para SVG mejorado
DOMPurify 2.x tenía soporte limitado para SVG. DOMPurify 3.0:
// ✅ DOMPurify 3.0 soporta SVG sanitizado
const svg = '<svg><circle cx="50" cy="50" r="40"/></svg>';
DOMPurify.sanitize(svg, { allowedTags: ['svg', 'circle'] });
// Devuelve: <svg><circle cx="50" cy="50" r="40"/></svg>
Pero es más estricto con scripts dentro de SVG:
// ❌ DOMPurify 3.0 rechaza scripts en SVG
const svgMalicioso = '<svg><script>alert(1)</script></svg>';
DOMPurify.sanitize(svgMalicioso);
// Devuelve: (string vacío)
DOMPurify 3.0 vs sanitize-html
sanitize-html: la alternativa de Node.js
sanitize-html es la librería que usamos en DevToolsHub (en lib/blog.ts). Funciona tanto en Node.js como en el navegador, pero está optimizada para Node.js.
import sanitizeHtml from 'sanitize-html';
const dirty = '<img src="x" onerror="alert(1)">';
const clean = sanitizeHtml(dirty, {
allowedTags: ['img'],
allowedAttributes: {
img: ['src']
}
});
// Devuelve: <img src="x">
Comparativa directa
| Característica | DOMPurify 3.0 | sanitize-html |
|---|---|---|
| Plataforma | Navegador (principal) | Node.js + Navegador |
| Rendimiento | Más rápido en navegador | Más rápido en Node.js |
| Configuración | Más simple | Más granular |
| SVG | Soporte nativo mejorado | Requiere configuración explícita |
| Custom tags | Fácil de añadir | Fácil de añadir |
| Mantenimiento | Cure53 (expertos seguridad) | Comunidad activa |
| Bundle size | 5KB minified | 12KB minified |
Cuándo usar DOMPurify 3.0
Usa DOMPurify 3.0 si:
- Tu código corre principalmente en el navegador
- Necesitas el máximo rendimiento en el cliente
- Usas SVG y necesitas soporte nativo
- Prefieres una API más simple
Cuándo usar sanitize-html
Usa sanitize-html si:
- Tu código corre en Node.js (backend)
- Necesitas configuración granular (por tag, por atributo)
- Prefieres una librería que funcione igual en ambos entornos
- Ya la usas y no quieres migrar
Migración desde DOMPurify 2.x a 3.0
Paso 1: Actualizar la API
// ❌ ANTES (DOMPurify 2.x)
DOMPurify.sanitize(dirty, {
ALLOWED_TAGS: ['b', 'i', 'a'],
ALLOWED_ATTR: ['href'],
SAFE_FOR_JQUERY: true
});
// ✅ DESPUÉS (DOMPurify 3.0)
DOMPurify.sanitize(dirty, {
allowedTags: ['b', 'i', 'a'],
allowedAttributes: ['href']
});
Paso 2: Eliminar opciones deprecadas
// ❌ ANTES
DOMPurify.sanitize(dirty, {
SAFE_FOR_JQUERY: true, // Eliminar
SANITIZE_DOM: true, // Eliminar (ahora siempre true)
RETURN_DOM: true, // Eliminar (ahora siempre string)
RETURN_DOM_FRAGMENT: true // Eliminar
});
// ✅ DESPUÉS
DOMPurify.sanitize(dirty, {
// Solo opciones relevantes
});
Paso 3: Ajustar reglas de sanitización
DOMPurify 3.0 es más estricto. Si tu HTML legítimo se elimina:
// Si esto se elimina en 3.0
const clean = DOMPurify.sanitize(dirty);
// Resultado: string vacío
// Añade explícitamente los tags que necesitas
const clean = DOMPurify.sanitize(dirty, {
allowedTags: ['b', 'i', 'a', 'img', 'p'],
allowedAttributes: {
a: ['href'],
img: ['src', 'alt']
}
});
Paso 4: Probar con tus datos reales
// Script de prueba
const testData = [
'<b>Negrita</b>',
'<a href="https://example.com">Enlace</a>',
'<img src="x" onerror="alert(1)">',
'<svg><circle cx="50" cy="50" r="40"/></svg>'
];
testData.forEach(dirty => {
const clean = DOMPurify.sanitize(dirty, yourConfig);
console.log(`Input: ${dirty}`);
console.log(`Output: ${clean}`);
console.log('---');
});
Migración desde sanitize-html a DOMPurify 3.0
Paso 1: Traducir configuración
// ❌ ANTES (sanitize-html)
sanitizeHtml(dirty, {
allowedTags: ['b', 'i', 'a'],
allowedAttributes: {
a: ['href', 'title'],
img: ['src', 'alt']
}
});
// ✅ DESPUÉS (DOMPurify 3.0)
DOMPurify.sanitize(dirty, {
allowedTags: ['b', 'i', 'a', 'img'],
allowedAttributes: ['href', 'title', 'src', 'alt']
});
DOMPurify usa un array plano para atributos, no un objeto por tag.
Paso 2: Traducir reglas especiales
// ❌ ANTES (sanitize-html)
sanitizeHtml(dirty, {
allowedSchemes: ['http', 'https'],
allowedSchemesByTag: {
img: ['http', 'https', 'data']
}
});
// ✅ DESPUÉS (DOMPurify 3.0)
DOMPurify.sanitize(dirty, {
allowedTags: ['a', 'img'],
allowedAttributes: ['href', 'src'],
// DOMPurify maneja schemes automáticamente
});
DOMPurify maneja schemes (javascript:, data:, etc.) automáticamente de forma segura.
Paso 3: Ajustar para SVG
// ❌ ANTES (sanitize-html)
sanitizeHtml(svgDirty, {
allowedTags: ['svg', 'circle', 'rect'],
allowedAttributes: {
'*': ['cx', 'cy', 'r', 'width', 'height']
}
});
// ✅ DESPUÉS (DOMPurify 3.0)
DOMPurify.sanitize(svgDirty, {
allowedTags: ['svg', 'circle', 'rect'],
allowedAttributes: ['cx', 'cy', 'r', 'width', 'height']
});
DOMPurify 3.0 tiene mejor soporte nativo para SVG, así que la migración es más simple.
Qué usar en DevToolsHub
Nuestro visor Markdown usa sanitize-html en el servidor. ¿Deberíamos migrar a DOMPurify 3.0?
Análisis
| Factor | sanitize-html | DOMPurify 3.0 |
|---|---|---|
| Backend (Node.js) | ✅ Optimizado | ⚠️ Funciona pero no optimizado |
| Frontend (navegador) | ⚠️ Funciona pero más lento | ✅ Optimizado |
| Markdown a HTML | ✅ Probado en producción | ⚠️ Necesita testing |
| SVG en Markdown | ⚠️ Requiere configuración | ✅ Soporte nativo |
Decisión
Por ahora, mantenemos sanitize-html porque:
- Nuestro código corre en el servidor (Next.js)
- Ya está probado en producción
- La configuración es granular y controlada
Pero si implementamos un visor Markdown en el cliente (puro navegador), migraríamos a DOMPurify 3.0 por su rendimiento superior.
Resumen: elige según tu caso
| Caso | Recomendación |
|---|---|
| Backend Node.js | sanitize-html |
| Frontend navegador | DOMPurify 3.0 |
| Isomórfico (ambos) | sanitize-html (mismo código) |
| SVG crítico | DOMPurify 3.0 |
| Máximo rendimiento navegador | DOMPurify 3.0 |
| Configuración granular | sanitize-html |
DOMPurify 3.0 es una excelente actualización, pero no es un reemplazo universal para sanitize-html. Cada librería tiene sus fortalezas.
Si usas DOMPurify 2.x, migra a 3.0. Los cambios de API son menores, y las mejoras de seguridad y rendimiento valen la pena.
Si usas sanitize-html, evalúa si necesitas las mejoras de DOMPurify 3.0. Si tu código corre principalmente en el navegador, la migración puede tener sentido. Si corre en Node.js, probablemente no.
La sanitización HTML no es algo donde debas improvisar. Usa una librería mantenida por expertos (Cure53 para DOMPurify, comunidad activa para sanitize-html), manténla actualizada, y prueba regularmente con payloads XSS reales.
Nuestro visor Markdown usa sanitize-html porque corre en el servidor y necesitamos configuración granular. Pero si implementamos un visor cliente, usaríamos DOMPurify 3.0 sin dudarlo.
Artículos relacionados
Nueva Vulnerabilidad en SHA-1: Por Qué Deberías Migrar a SHA-256 Ya
Recientes avances en ataques de colisión SHA-1 hacen que el algoritmo sea inseguro incluso para checksums de integridad. Guía de migración a SHA-256 para tus proyectos.
RFC 8259 Actualizado: Cambios en el Estándar JSON que Afectan a tus APIs
El estándar JSON ha recibido actualizaciones sobre manejo de Unicode, números grandes, y caracteres de control. Cómo afecta a tus herramientas de conversión y validación.
La Muerte de Date.parse(): Por Qué Usar Librerías de Fechas en 2026
Los navegadores modernos han deprecado comportamientos ambiguos de Date.parse(). Nuevas APIs temporales y por qué deberías usar librerías dedicadas.