A ChatGPT share link could run code in your session: postMessage → innerHTML → YouTube JSONP
Parameter Labs' chain bypassed the sandbox and the CSP without breaking either — the real perimeter was a sender check one open-source library omitted.
Parameter Labs has published a full account-takeover chain against ChatGPT: opening a public share link could run attacker-controlled JavaScript inside a signed-in user's session, read private conversations, and act on the account. Per Parameter Labs, OpenAI reproduced the report, fixed it on October 26, and paid a $5,000 bounty.
What shipped
The target was ChatGPT's HTML previews — the artifacts pattern (formerly Canvas), where an assistant-authored HTML block renders as an interactive app inside a sandboxed iframe. Parameter Labs (writeup, by Mukul Goyal) showed that a conversation containing one interactive graph plus one HTML preview could be shared as a normal /share/<id> link; a signed-in victim who opened it handed the attacker JavaScript execution on the chatgpt.com origin.
The chain, as the researchers describe it:
- The graph installs a listener. ChatGPT bundles the open-source MathLive library for graph support. Loading a graph "installed a listener in the main ChatGPT page for messages related to MathLive's on-screen keyboard."
- The preview sends a message. The sandboxed HTML preview iframe posts two messages to
top: amathlive#virtual-keyboard-messagewithaction: "update-setting"carrying attacker-supplied keyboard "layouts" (raw HTML), thenaction: "show". Sandboxing does not blockpostMessage, and MathLive's top-level controller "used an origin policy ofnone" — it accepted messages from any web address and never checked which frame sent them. innerHTMLin the parent. When the keyboard opened, MathLive joined the supplied layout into an HTML string and assigned it toinnerHTMLin the real ChatGPT page. A helper namedcreateHTMLlooked like a sanitizer but was a Trusted Types wrapper that passed the HTML through unchanged.- An unsandboxed iframe.
innerHTMLdoes not execute<script>elements, but it can inject an<iframe srcdoc="...">. Because the parent created it without asandboxattribute, the browser gave it thehttps://chatgpt.comidentity. Code inside could now access the parent page. - CSP bypass via YouTube oEmbed. OpenAI's CSP blocked inline scripts but allowed scripts from YouTube. YouTube's oEmbed endpoint reflects a JSONP
callbackparameter into its response — including into a 400 validation error. The payload usedcallback=globalThis.__marker=31337;void; the trailing;voidneutralized the object YouTube appended, and the browser executed the callback as a script inside the new frame. "Since YouTube was already allowed by ChatGPT's CSP, the browser loaded this response as a script and ran our callback inside the new frame." - Session access. With JavaScript on the
chatgpt.comorigin, the payload read the session data already present in the page and called ChatGPT's conversation APIs —GET /backend-api/conversationsto enumerate recent chats, thenGET /backend-api/conversations/<id>to read a private conversation that had never been shared — and exfiltrated a small piece of the response via an ordinary image request to a server the researchers controlled. "Essentially, we could perform any action on behalf of the victim's ChatGPT account."

Timeline: reported through OpenAI's bug bounty on October 18; OpenAI reproduced it October 21 and escalated severity from P2 to P1; fixed October 26; the writeup went public October 28. Bounty: $5,000.
Delivery was refined to a single click: in the final variant the HTML block was "marked as previewable so that ChatGPT opened it automatically. In that version, opening the link was the victim's only click." The researchers reproduced the automatic path three times in a separate account, with the alert appearing about 4.5 seconds after load.
Why it matters
The instructive part is what did not fail: the Preview sandbox held — code inside it could not read parent.document — and the CSP genuinely blocked inline scripts. Both were bypassed without being broken. The researchers' root-cause framing: "Three design decisions turned that mistake into a full exploit: MathLive accepted a state-changing message without proving which frame sent it. The message format allowed raw HTML to be supplied as keyboard-layout data. That HTML could create an unsandboxed document that inherited the chatgpt.com identity." The YouTube trick was "the final workaround for CSP, not the root cause."
For anyone building artifact or agent UIs, the transferable rules:
postMessagehandlers must checkevent.originandevent.source. The entire perimeter here was a sender check that one open-source library omitted. A static audit by dev.to's Sam LABBE of the shipped MathLive bundle found fourmessagelisteners with no sender check andinnerHTMLsinks. A ~100-line scan foraddEventListener('message')without.origin/.sourcecatches the class, though the author notes it is a heuristic, not a proof.- Sandboxed iframes can still talk to the parent.
sandboxrestricts DOM access, notpostMessage. Any message handler in the trusted page is reachable from untrusted frames. innerHTMLin a message handler is a code-execution sink. A Trusted Types wrapper is not a sanitizer.- CSP allowlists are only as safe as the most reflective endpoint on them. "YouTube in
script-src" means "YouTube decides what JavaScript runs on chatgpt.com" via a JSONP callback. oEmbed and JSONP endpoints in an allowlist are a bypass primitive. - An iframe created by the parent without
sandboxinherits the parent's origin.srcdocframes are not automatically sandboxed.

The second-order story: a full, link-based account takeover was priced at $5,000, and the security community is openly questioning whether that rate incentivizes the next disclosure. Simon Willison called it "a bit cheap for a vulnerability this serious."
Caveats
- There is no OpenAI advisory or CVE; the "fixed" status rests on Parameter's account and the bounty payment. The researchers report no real-world use, and their proof ran between their own accounts.
- The demonstrated scope was conversation enumeration and read/exfiltration. "Any action on behalf of the victim" is the researchers' inference from the session boundary, not a demonstrated capability — billing, files, and destructive actions were not shown.
- The full CSP
script-srcallowlist was never published; only YouTube is named in the sources. - MathLive's claimed fix (0.111.1/0.111.2) could not be confirmed from the project's GitHub releases page, which still showed 0.100.0 as latest at time of research.
- The October 13 "first confirmation against production code" date appears in only one secondary writeup.
Sources
- Parameter Labs — Do the Math: How We Took Over ChatGPT Accounts
- Simon Willison — How We Took Over ChatGPT Accounts
- Hacker News discussion
- The Hacker News — A Shared ChatGPT Link Could Run Attacker Code in Your Session and Read Private Chats
- dev.to (Gabriel Anhaia) — timeline and MathLive fix notes
- dev.to (Sam LABBE) — the chain and the static audit
- Samir Sengupta — independent reconstruction
- ctxsec briefing