Skip to content

Back to the catalog

parameter.aiwriteup

Do the math: How we took over ChatGPT accounts

Parameter Labs describes a chain that turned a public ChatGPT share link into JavaScript running as chatgpt.com in the victim's session. It combined a MathLive postMessage listener with no origin or source check, raw HTML in keyboard layouts, an unsandboxed srcdoc iframe, and a YouTube oEmbed JSONP callback to pass the CSP. The code read private conversations through backend APIs. OpenAI fixed it on 26 October 2026 and rated it P1.

TL;DR Chains a MathLive postMessage flaw, HTML injection, an unsandboxed iframe and a YouTube JSONP CSP bypass into ChatGPT account takeover from a shared link.
Document

What it is

Parameter Labs found a chain in the ChatGPT web frontend, fixed by OpenAI on 26 October 2026 and rated P1. A public /share/<id> conversation could run JavaScript as chatgpt.com in the session of anyone who opened it. The page names no CVE. The fix was server-side, so ChatGPT users have nothing to do.

How it works

The chain turns on two parts of one shared conversation that each look harmless alone.

flowchart LR
    A[Graph loads MathLive in main page] --> C[Listener accepts message]
    B[Preview iframe sends 2 messages] --> C
    C --> D[HTML set via innerHTML]
    D --> E[Unsandboxed srcdoc iframe, chatgpt.com origin]
    E --> F[YouTube oEmbed JSONP passes CSP]
    F --> G[Authenticated backend-api calls]
  • The graph makes MathLive install a postMessage listener in the main ChatGPT page. Its top-level controller used an origin policy of none and did not require the sender to be an approved window.
  • The sandboxed HTML Preview cannot read parent.document, but it can post two messages: one replaces the virtual keyboard layout with attacker HTML, the other shows the keyboard.
  • MathLive joins the layout into a string and assigns it to innerHTML. The createHTML helper only marks the string as trusted and does not sanitize it.
  • The injected iframe uses srcdoc and has no sandbox attribute. It gets a fresh document with the chatgpt.com origin, so it can reach the parent.
  • The CSP blocks inline script but allows YouTube. The oEmbed endpoint echoed the callback parameter into a text/javascript response before returning its validation error. Ending the callback with ;void swallowed the appended error object. Angle brackets were rewritten, so the payload avoided arrow functions.
  • The payload parsed #client-bootstrap for the access token and account ID. It called GET /backend-api/conversations?... and GET /backend-api/conversations/<id>?num_turns=2, then sent a small slice of a private conversation to an external server through an image request.

Preconditions / Affected

  • The victim only needs to open the attacker's share link while signed in to ChatGPT on the web. No app, project or pasted code is needed.
  • The first version used a researcher-controlled ChatGPT App as the sender. That was dropped once the graph and the assistant-authored HTML Preview were placed in one ordinary conversation.
  • The researchers reproduced the one-click variant (victim clicks Preview). They also reproduced an auto-open variant three times in a separate account, with the alert after about 4.5 seconds. The payload retried its messages for a limited period to win the load race with MathLive.
  • A native HTML attachment did not work alone, because the graph that installs the listener was lost on export to a public share.

What to do

The page's own guidance for anyone building similar surfaces:

  • Check both event.origin and event.source before acting on state-changing postMessage data.
  • Do not accept raw HTML in cross-window settings.
  • Keep dynamically created frames sandboxed when an untrusted frame can influence their content.
  • Treat CSP as a backup. Blocking only the YouTube endpoint would have left an untrusted Preview able to insert HTML into the page.

Caveats

  • OpenAI rolled the fix out across two frontend versions. CSP changes blocked part of the chain during rollout, and on 26 October OpenAI confirmed both versions rejected the cross-frame MathLive messages.
  • The proof read one private conversation and exfiltrated a small value. The claim of acting as the victim on other authenticated APIs is the authors' reasoning and was not demonstrated.

Organisations named here

  • OpenAI
  • Parameter Labs

Technologies named here

  • ChatGPT
  • YouTube
  • JavaScript
  • MathLive
  • YouTube oEmbed (Google)

Techniques named here

  • Cross-site scripting
  • Sandbox escape
  • Account takeover via shared link
  • JSONP callback abuse for CSP bypass
  • JSONP CSP bypass
  • postMessage origin validation
  • postMessage origin validation bypass

Concepts named here

  • Content Security Policy (CSP)
  • Origin validation
  • Sandbox escape