Un enlace compartido bastaba para secuestrar una cuenta de ChatGPT

Un enlace compartido bastaba para secuestrar una cuenta de ChatGPT

Una conversación pública de ChatGPT podía convertirse en una vía para ejecutar JavaScript con la sesión de la persona que abría el enlace. Parameter demostró que, encadenando un gráfico interactivo con una vista previa HTML, era posible consultar conversaciones privadas y enviar parte de su contenido a un servidor externo. Bastaba abrir el enlace en la variante automática del ataque; en una versión anterior, la víctima tenía que pulsar una vez el botón de vista previa.

OpenAI corrigió el problema en ambas versiones de su frontend web el 26 de octubre de 2026 y lo clasificó como P1, según Parameter. La empresa de seguridad recibió una recompensa de 5.000 dólares. No se ha informado de uso real de la vulnerabilidad: la prueba de acceso a chats privados se realizó entre cuentas controladas por los investigadores.

La salida no estaba en la vista previa, sino en el puente

La vista previa HTML de ChatGPT se ejecutaba dentro de un iframe aislado en otro dominio. Esa separación impedía que el contenido leyera directamente la página principal y los datos de la sesión. El aislamiento, por tanto, hacía su trabajo. El problema apareció cuando un segundo componente de la misma página ofreció una ruta indirecta para cruzar la frontera.

Un gráfico interactivo cargaba MathLive, una biblioteca JavaScript que también instala un receptor de mensajes para controlar su teclado virtual. El receptor aceptaba mensajes enviados mediante postMessage(). Parameter encontró que, en la configuración implicada, no verificaba de forma efectiva el origen ni la ventana que enviaba el mensaje. Además, uno de los cambios aceptados permitía suministrar HTML para definir la distribución del teclado.

La vista previa sandboxed no podía inspeccionar el documento principal, pero sí enviarle mensajes. El contenido malicioso aprovechaba esa capacidad para pedir a MathLive que sustituyera la distribución del teclado y luego lo mostrara. MathLive pasaba el marcado a innerHTML en la página real de ChatGPT. La función que parecía marcar el contenido como seguro no lo saneaba: la cadena llegaba intacta al punto de inserción.

El HTML inyectado creaba un iframe con srcdoc y sin atributo sandbox. Como lo generaba el documento principal, el navegador le asignaba la identidad de chatgpt.com. Quedaba un obstáculo: la política CSP de ChatGPT bloqueaba los scripts en línea. Parameter lo superó usando una respuesta JSONP del endpoint oEmbed de YouTube, cuyo dominio estaba permitido por esa política. El endpoint reflejaba el callback en una respuesta que, al cargarse como script, ejecutaba el JavaScript dentro del nuevo marco.

La secuencia combinó componentes que, por separado, tenían usos legítimos: un gráfico que inicializaba MathLive, una vista previa capaz de enviar mensajes, una inserción HTML sin saneamiento y una fuente de scripts permitida por CSP. El diagrama resume el recorrido descrito por Parameter.

flowchart TD
A["Atacante publica gráfico y vista previa"] --> B["Víctima abre el enlace compartido"]
B --> C["La vista previa envía mensajes"]
C --> D["MathLive acepta el cambio de teclado"]
D --> E["HTML entra en la página principal"]
E --> F["Iframe sin sandbox carga script permitido"]
F --> G["JavaScript actúa en la sesión"]
G --> H["API devuelve chats privados"]
H --> I["Datos salen a servidor externo"]

De leer una conversación a actuar como la cuenta

El resultado no era una alerta engañosa ni una modificación visual de la conversación compartida. El código ejecutado como chatgpt.com podía usar el contexto autenticado de la víctima para llamar a las API del frontend. Parameter enumeró conversaciones recientes, recuperó el contenido de una conversación privada que nunca se había compartido con el atacante y transmitió una parte de la respuesta a un servidor bajo control de los investigadores.

La diferencia importa: el robo no dependía de que la víctima tuviera abierta en pantalla la conversación privada. El JavaScript consultaba las API autenticadas de ChatGPT. Parameter señaló que esa capacidad podía extenderse a otras operaciones disponibles desde el frontend, y describió el alcance como actuar en nombre de la víctima. La demostración publicada probó lectura y exfiltración de contenido; no documentó una lista de cambios de cuenta ejecutados.

En la reproducción más estable, la víctima abría el enlace y pulsaba el botón normal de vista previa. Parameter consiguió después que el bloque se abriera automáticamente: en esa variante, visitar el enlace era la única interacción necesaria. Los investigadores reprodujeron ese comportamiento tres veces, incluso después de recargar la página, y observaron la alerta de prueba tras unos 4,5 segundos. Una carrera entre la carga del gráfico y la vista previa obligó a su código a reintentar los mensajes mientras MathLive terminaba de inicializarse.

La cadena también explica por qué bloquear YouTube no habría resuelto la causa. Esa carga proporcionó una forma de ejecutar JavaScript pese a la CSP, pero llegó después de que el HTML no confiable hubiera alcanzado la página principal. Quitar una ruta permitida habría cerrado ese método concreto para ejecutar código; el mensaje aceptado sin comprobar el emisor y la inserción de HTML seguirían siendo el problema estructural.

El parche y las obligaciones para quien integra componentes web

OpenAI reprodujo el fallo y desplegó correcciones en dos versiones del frontend. Durante el despliegue, cambios de CSP bloquearon parte de la cadena mientras una de las versiones aún necesitaba actualizarse. El 26 de octubre, ambas versiones rechazaban los mensajes de MathLive usados en el informe. Para quienes usan ChatGPT, la corrección se aplicó en el servicio: no hacía falta instalar ni restablecer nada.

La implicación para los equipos que integran MathLive o renderizan HTML de usuarios es más concreta que una advertencia general sobre contenido generado por modelos. Cada receptor de mensajes que cambie estado debe comprobar tanto event.origin como event.source: el dominio emisor y la ventana exacta autorizada. Validar solo el tipo del mensaje no basta si cualquier marco puede enviarlo.

También conviene mantener los datos de configuración como datos. Una estructura recibida entre ventanas no debería aceptar marcado HTML que termine en innerHTML. Si una aplicación necesita crear documentos a partir de contenido influido por usuarios o por una vista previa, esos documentos deben conservar el aislamiento adecuado; un iframe dinámico sin sandbox puede convertir una inyección de marcado en ejecución con la identidad del sitio anfitrión.

La CSP sigue siendo una defensa útil, pero en este caso actuó como una capa adicional, no como una barrera capaz de compensar el paso previo de HTML no confiable al documento principal. Parameter no identificó en su divulgación una versión de MathLive que corrigiera por sí sola el problema. Por eso, los equipos que incorporan la biblioteca deben revisar los controladores de mensajes y el punto donde se renderizan sus distribuciones, además de comprobar qué versión tienen desplegada.

El caso quedó reportado a OpenAI el 18 de octubre y fue resuelto ocho días después. Parameter recibió 5.000 dólares por el hallazgo. Para los usuarios, el enlace vulnerable ya no activa la cadena en el frontend corregido; para los desarrolladores, la pregunta pendiente está en sus propias integraciones: quién puede enviar mensajes a sus componentes y qué hace la página con el contenido que recibe.

Fuentes: Simon Willison’s Weblog, Parameter, Ostorlab Blog, Reveneau