Alta

markdown-it: Renderizado en tiempo cuadrático de una sola definición de referencia de enlace multilínea con opciones predeterminadas (regresión desde 14.0)

  • Publicada: 20.10.2026
  • Actualizado: 20.10.2026 23:23

Resumen

Una definición de referencia de enlace cuya etiqueta o título nunca se cierra tiene una complejidad O(n²) en markdown-it 15.0.2 con las opciones predeterminadas. Las líneas de continuación se obtienen de forma diferida con str += lineContent en src/rules_block/reference.ts, y las llamadas posteriores a charCodeAt y slice aplanan el cons-string de V8, copiando todo lo recopilado hasta el momento; esto se ejecuta antes de que la regla decida que la definición es inválida. Es una regresión introducida por el PR #1004 en 14.0.0: 13.0.2 procesaba una entrada de 313 KB en 125 ms, mientras que cualquier versión posterior tarda unos 11 segundos con la misma entrada. En los tamaños indicados abajo, 200 KB tarda 3.6 segundos, 400 KB tarda 18.1 segundos y 800 KB tarda 74.0 segundos, lo que equivale aproximadamente a 4–5× por duplicación. No se requiere ninguna opción especial para provocarlo.

Detalles

src/rules_block/reference.ts añade líneas de continuación con str += lineContent en las líneas 74, 83, 100, 133 y 150, y luego continúa indexando la cadena acumulada mediante str.charCodeAt(pos) en los bucles de etiqueta y espacios en blanco, y str.slice(...) en parseLinkTitle. V8 representa += como un cons-string, y la siguiente llamada a charCodeAt o slice lo aplana, copiando todo lo recopilado hasta el momento, por lo que una definición que abarca n líneas cuesta O(n²). El análisis en aislamiento confirma que esta regla es la causante: el análisis exclusivo de bloques con la funcionalidad inline desactivada sigue siendo cuadrático, md.disable('reference') hace que la misma entrada sea lineal, y el mismo texto sin el [ inicial es lineal. La corrección consiste en rastrear las posiciones en state.src en lugar de construir str, o recopilar fragmentos de línea en un array y analizarlos. Como mínimo, detener el escaneo de la etiqueta tras 999 caracteres (CommonMark §6.3) antes de solicitar más líneas, y limitar la continuación del título. Se debe añadir una prueba patológica con un título y una etiqueta no cerrados de 100k líneas. El PR abierto #1215 modifica el mismo archivo, pero su comprobación de etiquetas se ejecuta después del bucle de etiquetas, por lo que no limita ninguna de las dos variantes y la solución puede incorporarse junto con dicho PR.

La salida observada en la PoC fue: unclosed title n=100000 200009 B 3585.5 ms unclosed title n=200000 400009 B 18107.1 ms (5.05x) unclosed title n=400000 800009 B 73954.4 ms (4.08x)

Comparación de regresión a 313 KB: 13.0.2 → 125 ms, 14.1.0 → 11.4 s, 15.0.0 → 10.6 s, 15.0.2 → 10.7 s.

Prueba de concepto

Cómo ejecutar la PoC:

  1. mkdir -p markdown-it-poc && cd markdown-it-poc
  2. npm init -y
  3. npm i markdown-it@15.0.2
  4. node poc_markdown_it.js

La PoC es:

js
// poc_markdown_it.js
// Requires: npm install markdown-it@15.0.2
const MarkdownIt = require('markdown-it');
const md = new MarkdownIt();

function bench(label, src) {
  const t0 = process.hrtime.bigint();
  md.render(src);
  const t1 = process.hrtime.bigint();
  console.log(
    `${label.padEnd(30)} ${String(src.length).padStart(9)} B ${(Number(t1 - t0) / 1e6).toFixed(1).padStart(9)} ms`
  );
}

// Unclosed title: one reference definition spread over many lines
for (const n of [100000, 200000, 400000]) {
  bench(`unclosed title n=${n}`, '[a]: /u "' + 'x\n'.repeat(n));
}

// Unclosed label
for (const n of [5000, 10000, 20000]) {
  bench(`unclosed label n=${n}`, '[' + 'a\n'.repeat(n));
}

Impacto

Se trata de una denegación de servicio por complejidad algorítmica (CWE-407). Cualquier servidor que procese Markdown de usuarios con markdown-it bajo las opciones predeterminadas se ve afectado, incluidos comentarios, issues, chats, wikis, previsualizaciones de documentación e interfaces de chat de LLM. Un cuerpo de solicitud de ~400 KB bloquea el bucle de eventos de Node.js durante unos 18 segundos y uno de ~800 KB durante unos 74 segundos. Pertenece a la misma clase y modelo de atacante que GHSA-253c, pero es accesible sin activar opciones adicionales, ya que la ruta afectada es una regla de bloque principal.

Qué hacer

Actualice markdown-it a la versión 14.3.3, 15.0.3 o posterior. Como mitigación temporal, puede desactivar la regla afectada utilizando md.disable('reference') si no se requieren definiciones de referencia de enlaces.

Software afectado

Haz clic en una tecnología para ver todas sus vulnerabilidades.

PlataformaPaqueteVersiones vulnerablesCorregida en
Paquete de npm markdown-it >= 14.1.0, < 14.3.3, >= 15.0.0, < 15.0.3 14.3.3, 15.0.3

Referencias

Puntuación CVSS 7.5/10
Vector CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Debilidad (CWE)
CWE-400, CWE-407
Plataforma
npm
Paquete
markdown-it
Publicada
20.10.2026
Actualizado
20.10.2026 23:23

Fuentes y licencias · Editado o traducido por DockRay; se mantienen los derechos y las licencias de las fuentes.

OSV / GitHub Advisory Database - GHSA-gfr2-rv44-r23c - CC BY 4.0

Historial de vulnerabilidades: markdown-it

Todas las vulnerabilidades publicadas de este paquete (Paquete de npm), de la más reciente a la más antigua. Muestra si es un fallo aislado o un paquete que hay que vigilar.

Entradas en total
8
Primera → última
01.2022 10.2026
Sin corrección
0
Explotada en ataques
0

Distribución por gravedad

  • Alta 3
  • Media 4
  • Baja 1

Divulgaciones por año

  1. 2022: 2
  2. 2023: 0
  3. 2024: 0
  4. 2025: 0
  5. 2026: 6
  1. markdown-it: Renderizado en tiempo cuadrático de una sola definición de referencia de enlace multilínea con opciones predeterminadas (regresión desde 14.0) esta entrada
    Alta · 7.5 CVE-2026-111758 >= 14.1.0, < 14.3.3, >= 15.0.0, < 15.0.3 14.3.3, 15.0.3
  2. Baja · 3.7 CVE-2026-111766 < 14.3.3, >= 15.0.0, < 15.0.3 14.3.3, 15.0.3
  3. Alta · 7.5 CVE-2026-111759 >= 15.0.0, < 15.0.2, < 14.3.2 15.0.2, 14.3.2
  4. Media · 5.3 CVE-2026-2327 >= 13.0.0, < 14.1.1 14.1.1
  5. Media · 5.3 CVE-2022-21670 < 12.3.2 12.3.2

Identifica las vulnerabilidades de tu aplicación

Con la integración de DockRay y el inventario de software activado, DockRay compara las versiones notificadas de los componentes con las vulnerabilidades conocidas y avisa de las coincidencias confirmadas. La cobertura depende de la tecnología compatible y de los avisos disponibles.

Conectar tu aplicación
Newsletter DockRay

La seguridad de tus aplicaciones en tu correo

Vulnerabilidades importantes, recomendaciones concretas y consejos prácticos para tus aplicaciones. Elige tus tecnologías y sigue lo que importa para tu proyecto.

  • Un resumen diario de nuevas vulnerabilidades, también las críticas.
  • Avisos sobre actualizaciones importantes.
  • Consejos prácticos sobre seguridad y monitorización de aplicaciones.

Déjalo vacío para recibir avisos de todas las tecnologías.

Suscripción gratuita. Date de baja con un clic en cualquier correo.