Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-32722 — XSS almacenado de Bloomberg Memray a través de metadatos de línea de comandos sin escapar | Kitploit
Herramientas/GitHubGitHub/0xmrma/cve-2026-32722
Análisis Estático de Código (SAST)Análisis de VulnerabilidadesExplotación de Aplicaciones WebPruebas de PenetraciónPapers e InvestigaciónAprendizaje y Educación
GitHub0xmrma/cve-2026-32722

CVE-2026-32722

XSS almacenado de Bloomberg Memray a través de metadatos de línea de comandos sin escapar

Ver Repositorio
17hace 5 mesesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2026-32722

XSS almacenado en Bloomberg Memray mediante metadatos de línea de comandos sin escapar

Introducción

Encontré este problema al revisar Memray, el perfilador de memoria de Python de Bloomberg, con una pregunta simple en mente:

¿Pueden los metadatos de tiempo de ejecución controlados por el atacante cruzar de forma insegura hacia la salida del informe renderizada en el navegador?

En este caso, la respuesta fue sí.

El error estaba en la ruta de generación de informes HTML de Memray, donde los metadatos de la línea de comandos se renderizaban en un informe abierto en el navegador sin escapar. Eso convirtió un campo operativo en un sumidero HTML ejecutable y, finalmente, se convirtió en CVE-2026-32722.

Proyecto: Memray en GitHub
Aviso: GHSA-r5pr-887v-m2w9 / CVE-2026-32722

photo0

Cadena de ataque

argv controlado por el atacante → metadata.command_line → sumidero de plantilla HTML sin escapar → marcado sin procesar en el informe generado → ejecución de JavaScript en el navegador


Qué hace Memray

Memray es un perfilador de memoria de Python.

Instrumenta un proceso de Python, registra el comportamiento de asignación y produce informes que ayudan a los desarrolladores a comprender:

  • dónde se asigna la memoria
  • qué rutas de llamada son responsables
  • cómo es el uso máximo de memoria
  • cómo cambia la memoria con el tiempo

Algunos de esos informes se emiten como HTML y se abren en un navegador.

Eso hace que la generación de informes sea un límite de seguridad real.

La pregunta relevante no es si Memray es una "herramienta local".
La pregunta relevante es si los datos controlados por el atacante pueden cruzar de forma insegura hacia la salida renderizada en el navegador.

En este caso, podían.


Por qué valía la pena investigar este error

Mucha gente subestima las herramientas para desarrolladores.

Eso es un error.

Una vez que una herramienta:

  • registra metadatos de tiempo de ejecución,
  • almacena valores influenciados por el atacante,
  • y luego los renderiza en HTML,

hereda los mismos riesgos de codificación de salida que una aplicación web.

Ese fue el problema central aquí.

Este error no estaba en la lógica de perfilado. No estaba en el seguimiento de asignaciones. No estaba en el manejo nativo de memoria.

Era una clásica falla de límite de confianza:

  • metadatos no confiables entraron al sistema,
  • cruzaron hacia un sumidero HTML,
  • y se renderizaron sin escapar.

Eso es suficiente para crear una vulnerabilidad real.


El límite en el que me centré

No abordé Memray fuzzeando opciones aleatorias de CLI ni persiguiendo caídas del sistema.

El enfoque más sólido era identificar primero la superficie de seguridad de mayor probabilidad.

Para Memray, esa era la generación de informes HTML.

¿Por qué?

Porque la salida HTML introduce un sumidero en el navegador, y los sumideros del navegador convierten errores comunes de metadatos en problemas de seguridad si:

  • la entrada está influenciada por el atacante,
  • la salida no está escapada,
  • y el navegador interpreta el resultado como marcado en lugar de texto.

Eso es exactamente lo que sucedió aquí.


Causa raíz

El error se reduce a dos líneas.

En:

root@kitploit:~
def get_render_environment() -> jinja2.Environment:
    loader = jinja2.PackageLoader("memray.reporters")
    env = jinja2.Environment(loader=loader)

el entorno Jinja se crea sin autoescape.

Luego en:

root@kitploit:~
Command line: <code>{{ metadata.command_line }}</code><br>

metadata.command_line se renderiza directamente en HTML.

Esa es toda la vulnerabilidad.

Por qué esto es explotable

Porque metadata.command_line está influenciado por el atacante.

Memray registra la línea de comandos utilizada para ejecutar el programa perfilado. Eso significa que los valores controlados por el usuario de argv se conservan como metadatos y luego se insertan en el informe.

Entonces la cadena de explotación es sencilla:

  • el atacante controla el contenido de la línea de comandos
  • Memray lo almacena en metadata.command_line
  • la plantilla lo emite en HTML
  • el entorno no lo escapa automáticamente
  • el navegador lo parsea como marcado vivo

Eso convierte los metadatos en contenido ejecutable en el navegador.


Qué convierte esto en un problema de seguridad, no solo en un renderizado deficiente

La distinción importante es la ejecución.

Muchos errores producen HTML malformado. Eso por sí solo no es suficiente.

Aquí, el contenido controlado por el atacante no solo era visible en el código fuente de la página. El navegador lo interpretaba como HTML activo y lo ejecutaba como JavaScript.

Esa es la diferencia entre:

  • corrupción del formato
  • y un sumidero XSS real

Entonces la pregunta no era:

"¿Puede aparecer HTML en el informe?"

La pregunta real era:

"¿Puede el HTML controlado por el atacante volverse ejecutable cuando se abre el informe?"

La respuesta fue sí.


PoC

Mi reproducción inicial usaba un script explícito más un argumento controlado por el atacante:

root@kitploit:~
cat > victim.py <<'PY'
x = [b"A" * 1024 for _ in range(1000)]
print("done")
PY

python -m memray run -o poc.bin victim.py ''
python -m memray flamegraph -o poc.html poc.bin

El HTML generado contenía marcado sin procesar controlado por el atacante:

root@kitploit:~
Command line: <code>~/memray/src/memray/__main__.py run -o poc.bin victim.py </code><br>

Abrir o actualizar el informe generado provocaba la ejecución de JavaScript.

Eso estableció la afirmación central:

  • el valor no estaba escapado,
  • el navegador lo parseaba como marcado,
  • y el sumidero era ejecutable.

Más tarde, durante la divulgación coordinada, el mantenedor simplificó aún más la reproducción:

root@kitploit:~
python -m memray run -o poc.bin -c '# '

Esa versión es mejor porque aísla el límite vulnerable de forma más directa:

  • sin archivo adicional
  • sin lógica de aplicación adicional
  • solo contenido de línea de comandos controlado por el atacante entrando en la canalización del informe

Por qué se eligió el payload

El payload fue intencionalmente simple:

root@kitploit:~

Esto no se trata de payloads llamativos.

Es una sonda de ejecución limpia porque:

  • no requiere infraestructura externa
  • es obvio en el HTML renderizado
  • demuestra la interpretación HTML de inmediato
  • demuestra la ejecución en el navegador sin depender de contenido remoto

Para esta clase de errores, eso es suficiente.


Validación del alcance

Un solo tipo de informe ya habría sido suficiente para justificar el problema.

Pero quería saber si esto estaba aislado o era estructural.

Confirmé el mismo comportamiento en:

  • informes flamegraph
  • informes de tabla
  • informes flamegraph generados con --no-web

Eso importaba por dos razones.

Primera

Mostró que el sumidero vulnerable se reutilizaba en múltiples salidas HTML.

Segunda

Demostró que el error no dependía de recursos externos alojados en CDN.

--no-web seguía reproduciendo el problema, lo que significa que el fallo estaba en el HTML generado por el propio Memray y en el manejo de plantillas, no en el comportamiento de JS remoto. Eso hizo que el caso fuera mucho más sólido.


Por qué se clasificó como severidad baja

La principal preocupación del mantenedor era el control práctico del atacante.

Eso es justo.

Este no es el tipo de problema donde un atacante remoto no autenticado golpea un endpoint HTTP expuesto y obtiene impacto inmediato.

La condición de explotación es más estrecha:

  • el atacante influye en la entrada de la línea de comandos
  • una víctima abre posteriormente el informe generado en un navegador

Entonces la clasificación realista era severidad baja.

Eso no lo convierte en un error débil.

La severidad trata sobre las condiciones de explotación y el impacto probable. La validez trata sobre si el problema es real.

Este problema era claramente real:

  • fuente controlada por el atacante
  • sumidero HTML
  • falta de escape
  • ejecución real de JavaScript
  • corrección determinista

Por eso aun así se convirtió en un CVE.


Análisis de la corrección

La corrección fue mínima y correcta.

El mantenedor cambió:

root@kitploit:~
{{ metadata.command_line }}

a:

root@kitploit:~
{{ metadata.command_line|e }}

Esa es la corrección adecuada porque aborda directamente el sumidero vulnerable.

En lugar de emitir marcado sin procesar como:

root@kitploit:~

la plantilla ahora emite texto escapado:

root@kitploit:~
&lt;img src=x onerror=alert(1)&gt;

Eso preserva el valor informativo del campo de línea de comandos mientras elimina la ruta de ejecución en el navegador.

El mantenedor también revisó el resto del contexto de la plantilla y concluyó que:

  • varios campos eran numéricos
  • algunas cadenas estaban completamente controladas por Memray
  • los valores vinculados a scripts se renderizaban con |tojson Así que el problema se acotó correctamente a metadata.command_line.

Ese es exactamente el tipo de revisión de corrección que quieres en una divulgación real.


Divulgación

Esto se reportó de forma privada a través de GitHub Security Advisories.

Los mantenedores:

  • validaron el problema
  • aceptaron que era su error para corregir
  • simplificaron la reproducción
  • parchearon el sumidero vulnerable
  • publicaron la corrección en 1.19.2
  • solicitaron un CVE
  • publicaron el aviso

Al problema se le asignó: CVE-2026-32722


Qué enseña realmente este error

La lección clave aquí es simple:

los metadatos no son automáticamente confiables solo porque parecen operativos.

  • Una línea de comandos parece inofensiva.
  • Un modal de informe parece inofensivo.
  • Un archivo HTML local parece inofensivo.

Nada de eso importa una vez que el contenido controlado por el atacante cruza hacia la salida renderizada en el navegador sin escapar.

En el momento en que una herramienta emite HTML, debe tratarse como una aplicación que produce HTML.

Esa es la verdadera conclusión.


Puntos clave

  • Los generadores de informes HTML son superficies de seguridad
  • las herramientas para desarrolladores también necesitan disciplina de codificación de salida
  • los artefactos de informes locales pueden contener sumideros XSS reales
  • la falta de escape en las plantillas es suficiente cuando los metadatos controlados por el atacante llegan al sumidero
  • la severidad baja no significa baja calidad
  • la mentalidad correcta aquí fue el análisis de límites de confianza, no el fuzzing a ciegas

Palabras finales

Esta vulnerabilidad no se trataba de un payload inteligente.

Se trataba de identificar el límite correcto.

Memray tomó metadatos de línea de comandos influenciados por el atacante y los renderizó en HTML generado sin escaparlos. El navegador hizo el resto.

Por eso esto se convirtió en CVE-2026-32722.

Corregido en Memray 1.19.2.

photo0
Descargar herramienta