FlawOpen

flawopen.com/ReDoS/JavaScript RegExp

¿JavaScript RegExp es vulnerable a ReDoS?

CWE-1333: Inefficient Regular Expression ComplexityPágina de referencia
Respuesta breve

Imagina a un empleado que prueba todas las formas de dividir una pila de formularios cuando falta la marca final: un patrón ambiguo puede obligar al motor regex a revisar muchos caracteres una y otra vez. La ruta habitual de RegExp en V8 puede retroceder así; limitar la entrada y usar un patrón de coste predecible acota el trabajo. En Node, la coincidencia síncrona se ejecuta en el hilo del event loop y retrasa otros callbacks del proceso. V8 documenta un motor experimental sin backtracking, activado mediante flags y con limitaciones de patrones; no des por hecho que esté habilitado en producción.

VULNERABLE
// Repetición anidada ambigua sobre datos de la solicitud
const re = /^(\w+\s?)*$/;

app.post('/search', (req, res) => {
  const q = req.body.q;
  if (!re.test(q)) return res.sendStatus(400);
  res.sendStatus(200);
});
CORREGIDO
// Limita la entrada y acepta solo la gramática del campo
app.post('/search', (req, res) => {
  const q = req.body.q;
  if (typeof q !== 'string' || q.length > 128)
    return res.sendStatus(400);

  // Gramática de ejemplo: caracteres ASCII de palabra y espacios
  if (!/^[\w ]{1,128}$/.test(q))
    return res.sendStatus(400);

  res.sendStatus(200);
});

Por qué Node.js amplifica el impacto de ReDoS

La coincidencia síncrona de una expresión regular se ejecuta en el hilo JavaScript que atiende callbacks en un proceso Node.js. Si el patrón tarda con una entrada casi coincidente o fallida, ese event loop no puede ejecutar otros callbacks ni avanzar solicitudes hasta que termine. Los workers, varios procesos o réplicas pueden conservar parte de la capacidad, pero cada proceso afectado aún puede quedar bloqueado.

El impacto depende de la alcanzabilidad, complejidad del patrón, límites de entrada y topología. El atacante debe alcanzar la coincidencia vulnerable con una entrada que active su ruta costosa. Trátalo como riesgo de disponibilidad para el proceso afectado; que caiga todo el servicio depende de workers, réplicas, enrutamiento y comprobaciones de salud.

Caso real en npm: CVE-2026-83606 en xmldom

El aviso revisado de @xmldom/xmldom registra CWE-1333 en el análisis de instrucciones de procesamiento: la gramática vulnerable permite que un grupo codicioso de espacios y otro perezoso de datos consuman los mismos espacios. Si falta el cierre ?>, el parser prueba muchas particiones y tarda tiempo cuadrático. Afecta a las versiones 0.9.0-beta.9 a 0.9.10; 0.9.11 lo corrige impidiendo que el separador devuelva espacios al grupo de datos. El aviso limita el problema a la ruta 0.9.x del paquete con ámbito; no señala como afectados 0.8.x ni el paquete sin ámbito.

La auditoría de dependencias ayuda, pero no demuestra que las regex sean seguras

npm audit informa de avisos conocidos asociados a dependencias del árbol del proyecto; no analiza todas las regex del código ni descubre fallos ReDoS sin publicar. Mantén actualizadas las dependencias directas y transitivas, revisa las rutas afectadas e inspecciona aparte los patrones que procesan texto controlado por usuarios.

npm audit --omit=dev

La auditoría cubre avisos conocidos, no todos los riesgos regex. Revisa el informe según tu despliegue y evalúa por separado si una entrada no confiable puede llegar a una coincidencia costosa y si su tamaño está limitado.

Preguntas frecuentes

¿Puedo establecer un timeout para una regex de JavaScript?

La API RegExp no ofrece un timeout por coincidencia. Prefiere patrones simples y limita la entrada antes de comparar. Si necesitas una coincidencia compleja, aísla el trabajo en un worker o proceso hijo con un plazo de terminación efectivo; esto limita el impacto, pero no vuelve eficiente el patrón.

¿También afecta al JavaScript del navegador?

Sí. Una coincidencia síncrona patológica puede congelar el hilo principal de la página hasta que termine y bloquear la interfaz. Limita la entrada, simplifica el patrón y evita ejecutarlo con cada tecla.

¿Es seguro usar new RegExp(userInput) en una búsqueda?

Trata los patrones del usuario como entrada ejecutable para un motor potencialmente costoso. No aceptes patrones arbitrarios en un servidor sin límites estrictos y aislamiento. Si solo se necesita búsqueda literal, escapa la entrada como literal regex o usa APIs de búsqueda de texto; escapar evita cambios sintácticos, pero no sustituye el límite de tamaño.

Referencias y correcciones

Véase también ¿Qué es ReDoS (retroceso catastrófico)?