
CVE-2026-74945, divulgación de memoria heap no inicializada mediante una fuente web manipulada (sec-high)
Este directorio contiene un paquete de reproducción honesto para una divulgación
de memoria no inicializada en el manejo de fuentes de Firefox. Una fuente
@font-face manipulada lleva el flujo de salida de OTS hacia un hueco de
heap no inicializado, y el contenido ordinario lee bytes de ese hueco a través
de la API measureText del canvas. Está pensado para ejecutarse contra
una compilación vulnerable de Firefox descargada localmente con datos
sintéticos únicamente. Nunca toca ningún sistema activo ni de terceros.
Repositorio PoC correspondiente: https://github.com/defineid/Palimpsest
Análisis: writeup-font-cmap-leak.html en este portafolio.
| Campo | Valor |
|---|---|
| CVE | CVE-2026-74945 |
| Componente | Core / Graphics: Text |
| Clase | Divulgación de memoria no inicializada (CWE-908 · CWE-200) |
| Gravedad | sec-high (divulgación de memoria accesible desde la web) |
| Corregido en | Firefox 154 · ESR 140.14 |
| Bug | bugzilla.mozilla.org/show_bug.cgi?id=2057808 |
| Interacción | Ninguna · solo carga de página |
Firefox sanitiza las fuentes web a través de OTS antes de usarlas. Tres defectos independientes se alinean para que una fuente manipulada deje un hueco de heap no inicializado dentro de la salida sanitizada y el contenido pueda leerlo de vuelta:
moz_xrealloc) que no
rellena con ceros el espacio nuevo.cmap de formato 14 con
un nonDefaultUVSOffset grande hace que OTS avance su flujo de salida al
re-serializar la fuente sanitizada. El tramo omitido entre los bytes escritos
y el destino del seek se entrega al llamador con heap no inicializado, y
forget() dimensiona el búfer hasta el mayor desplazamiento alcanzado.cmap en lugar de la subtabla, por lo que un segmento cuyo
idRangeOffset se sale del final de los datos de formato 4 sigue pasando la
comprobación y lee dentro de los bytes no inicializados de la subtabla
vecina.La fuente manipulada combina una subtabla de formato 4, cuyo último segmento
(0xFFFF) usa un idRangeOffset impar que se desborda, con una subtabla de
formato 14 que lleva un nonDefaultUVSOffset grande, además de
maxp.numGlyphs = 65535 y un avance hmtx distinto por id de glifo (avance ==
id de glifo). Medir U+FFFF por lo tanto resuelve a un id de glifo leído del
hueco no inicializado, y su ancho de avance, legible desde el script, divulga
unos dos bytes de heap por medición sobre una ventana de aproximadamente 64 KB.
Una página web ordinaria sirve la fuente manipulada a través de @font-face y
llama a ctx.measureText(""). No se requiere clic, permiso, extensión ni
cambio de preferencia. OTS se ejecuta en proceso y no está entre las
bibliotecas en sandbox, por lo que los bytes divulgados son heap del proceso de
contenido que puede contener punteros o secretos.
| Archivo | Propósito |
|---|---|
make_font.py | Construye leak.otf y leak.woff, las fuentes manipuladas. |
trigger.html | Página básica que carga la fuente mediante @font-face y lee el avance de U+FFFF de vuelta a través de measureText. |
https://ftp.mozilla.org/pub/firefox/releases/140.9.0esr/.pip install fonttools brotli
python3 make_font.py # writes leak.otf and leak.woff in this directory
Luego abre trigger.html en la compilación vulnerable, desde una ruta file:// o un servidor estático local que controles, y haz clic en Measure.
.notdef) y el avance es 0. No se filtra ningún hueco, porque el flujo de salida se pone a cero y la búsqueda de formato 4 está acotada a su propia subtabla.make_font.py se ejecutó aquí con fontTools 4.63.0 y produjo leak.otf (393816 bytes) y leak.woff (132372 bytes). La fuente generada se volvió a analizar desde los bytes en bruto y se confirmó cada ingrediente fabricado: maxp.numGlyphs = 65535, hhea.numberOfHMetrics = 65535, un avance hmtx distinto por id de glifo (avance == id de glifo), dos subtablas cmap (plataforma 3 codificación 1 formato 4, y plataforma 0 codificación 5 formato 14), el último segmento del formato 4 endCode = 0xFFFF con un idRangeOffset = 0x4001 impar que se desborda, y el nonDefaultUVSOffset = 0x8000 del formato 14.trigger.html tú mismo contra una compilación vulnerable local para observar la fuga. Este paquete demuestra la entrada fabricada y la ruta de lectura de vuelta; no es un exploit armado e incluye ninguna primitiva controlada de ejecución de código.Esto se dirige a una compilación descargada localmente con datos de fuente sintéticos y autogenerados, para un informe sobre el CVE del propio autor, ya reportado y parcheado. No ataca ningún servicio en vivo ni de terceros.