Skip to content
FA Ferdous Azad

How Parameter Labs Hijacked ChatGPT Accounts via HTML Previews

Discover the detailed attack chain that let untrusted HTML previews take over ChatGPT accounts, the sandbox failures, and lessons for developers building LLM‑driven UIs.

#TL;DR

Parameter Labs uncovered a multi‑stage exploit in ChatGPT’s “HTML previews” (formerly “Canvas”). By abusing the MathLive library’s postMessage interface, an attacker could inject unsandboxed iframes, bypass CSP via YouTube’s oEmbed endpoint, and run JavaScript in the parent page. The resulting code could read a signed‑in user’s private data and exfiltrate it, effectively hijacking any ChatGPT account that visited a malicious share link. OpenAI patched the bug and issued a $5 000 bounty.


#What’s new

Feature Description Security notes
HTML previews (aka “Canvas”) Allows developers to embed interactive custom HTML apps inside a sandboxed <iframe> on a ChatGPT conversation. Intended to be isolated from the parent page and from OpenAI APIs.
MathLive integration A JavaScript library used for rendering math graphs; includes a virtual keyboard that can be triggered via postMessage. The message handler writes the payload into innerHTML of the parent, creating a path for HTML injection.
CSP policy Blocks inline scripts and restricts external scripts to a whitelist of domains. YouTube’s oEmbed endpoint is on the whitelist, unintentionally enabling script reflection.

These components were introduced to make ChatGPT more interactive, but the combination opened a chain of trust violations that Parameter Labs turned into a full‑account takeover.


#How the attack chain works

Note

The following diagram abstracts the flow; each arrow represents a single step in the exploit.

flowchart TD
    A["Attacker crafts malicious HTML preview"] --> B["Iframe loads MathLive library"]
    B --> C["Attacker sends postMessage to parent"]
    C --> D["Parent handler uses innerHTML to insert attacker HTML"]
    D --> E["Injected iframe lacks sandbox attribute"]
    E --> F["CSP allows script from YouTube oEmbed"]
    F --> G["YouTube oEmbed reflects attacker‑controlled JS"]
    G --> H["JS runs in ChatGPT context"]
    H --> I["Calls OpenAI APIs with user token"]
    I --> J["Exfiltrates data via <img src>"]
    J --> K["Attacker gains account control"]

#Step‑by‑step breakdown

  1. Craft a malicious HTML preview – The attacker creates an HTML snippet that loads the MathLive library (required for graph rendering).
  2. Trigger the virtual keyboard – From inside the sandboxed iframe, the attacker calls postMessage to the parent page, requesting the virtual keyboard.
  3. Parent processes the message – ChatGPT’s message‑handling code inserts the received payload into the DOM using innerHTML. No validation is performed, and the code does not restrict which sandboxed frames may invoke it.
  4. Inject an unsandboxed iframe – Because innerHTML can embed arbitrary tags, the attacker adds a new <iframe> without a sandbox attribute, breaking the isolation model.
  5. Leverage CSP whitelist – The CSP blocks inline scripts but permits loading scripts from a small set of domains, including youtube.com.
  6. Use YouTube oEmbed for script reflection – The attacker points the unsandboxed iframe to YouTube’s oEmbed endpoint, which returns a JSON payload that can contain a <script> tag with attacker‑controlled JavaScript.
  7. Execute JavaScript in the ChatGPT page – The reflected script runs with the same privileges as the ChatGPT UI, giving the attacker access to the logged‑in user’s session token and API keys stored in browser memory.
  8. Fetch private data – The malicious script calls OpenAI’s internal APIs (e.g., /v1/users/me) to retrieve conversation history, saved files, and other personal data.
  9. Exfiltrate via an image request – Data is encoded into a URL and sent to the attacker’s server using an <img src> tag, bypassing most CSP‑based data‑leak protections.

The end result is a shareable URL that looks innocuous but, when opened by any signed‑in user, silently steals their account data or performs actions on their behalf.


#How it compares to prior ChatGPT sandbox issues

Aspect Earlier Canvas bugs (2023‑2024) HTML previews exploit (2026)
Root cause Overly permissive allow-scripts in sandbox attribute. innerHTML injection + CSP whitelist misuse.
Attack surface Direct script execution inside iframe. Cross‑frame postMessage → DOM injection → CSP bypass.
Complexity Single‑step script injection. Multi‑stage chain requiring three distinct components (MathLive, postMessage, YouTube oEmbed).
Impact Limited to the iframe’s origin. Full account takeover across any signed‑in user.
Mitigation Tighten sandbox flags, disallow allow-scripts. Validate postMessage origins, avoid innerHTML, restrict CSP whitelist.

The 2026 exploit is more sophisticated because it combines a legitimate third‑party library (MathLive) with a CSP misconfiguration, illustrating how “trusted” dependencies can become attack vectors when their integration points are not hardened.


#How to try safe HTML previews (or reproduce the bug in a controlled environment)

Tip

Never test the live exploit on production accounts. Use an isolated browser profile with no logged‑in OpenAI session.

Below is a minimal example of a secure HTML preview that respects the same sandboxing constraints but avoids the vulnerable innerHTML path. The code demonstrates how to listen for postMessage safely and inject content using DOM APIs that do not evaluate scripts.

Python
# Install the OpenAI Python client (if you haven't)
# pip install openai

import openai

# Create a shareable preview that only displays static HTML.
# Replace <YOUR_API_KEY> with a test key that has no real user data.
client = openai.ChatCompletion.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "user", "content": "Show a simple math graph using MathLive."}
    ],
    # The `artifacts` field is where HTML previews are attached.
    artifacts=[
        {
            "type": "html",
            "content": """
                <html>
                <head>
                  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/mathlive.min.js"></script>
                </head>
                <body>
                  <math-field id="mf"></math-field>
                  <script>
                    // Safe message handling – only accept messages from our own iframe.
                    window.addEventListener('message', (e) => {
                      if (e.origin !== location.origin) return;
                      const {type, payload} = e.data;
                      if (type === 'setLatex') {
                        document.getElementById('mf').setValue(payload);
                      }
                    });
                  </script>
                </body>
                </html>
            """
        }
    ]
)

print("Share URL:", client["share_url"])

Key safety points in the snippet

  • The preview uses a static script from a trusted CDN; no dynamic script loading is allowed.
  • The postMessage handler checks e.origin against location.origin, preventing other iframes from injecting messages.
  • Content is inserted via the MathLive API (setValue) instead of innerHTML.

If you need to test the vulnerability itself, spin up a local HTML file that mimics the MathLive postMessage call and observe that the parent page’s innerHTML insertion leads to an unsandboxed iframe. Do this only in a disposable environment with no real credentials.


#Limitations and open questions

  • Dependency‑driven risk – The exploit hinged on MathLive’s virtual keyboard exposing a postMessage entry point. Are other third‑party widgets (e.g., charting libraries, code editors) exposing similar surfaces? A systematic audit of all embedded libraries is required.
  • CSP whitelist granularity – OpenAI’s CSP allowed any script from youtube.com. Should CSP be expressed with stricter sub‑resource integrity (SRI) hashes or nonce‑based policies to prevent reflection attacks?
  • Sandbox enforcement – The current sandbox attribute on the preview iframe does not prevent the parent from writing to its own DOM. Would a “double‑sandbox” model (parent also sandboxed) mitigate this class of attacks?
  • Bug bounty sizing – Parameter Labs received $5 000 for a vulnerability that enables full account takeover. The community is debating whether the reward reflects the true risk. Future bounty programs may need tiered payouts based on potential impact.
  • Detection – The attack chain leaves minimal network traces because the exfiltration occurs via an <img> request. Are there reliable client‑side heuristics (e.g., sudden creation of unsandboxed iframes) that can flag malicious previews in real time?

#FAQ

Q: Can I still use HTML previews safely after the patch?
A: Yes. OpenAI now validates the origin of postMessage events, rejects any payload that attempts to set innerHTML, and removed YouTube from the CSP whitelist for preview contexts.

Q: Does the exploit affect other OpenAI products like DALL·E or Whisper?
A: The vulnerability is specific to the ChatGPT UI’s HTML preview implementation. Other products that do not embed arbitrary HTML are not directly impacted.

Q: Should I audit my own LLM‑driven web apps for similar issues?
A: Absolutely. Any feature that lets users supply HTML, JavaScript, or other executable content should be isolated with a strict CSP, avoid innerHTML, and verify message origins before acting on them.


#Key takeaways

  • Sandboxing is only as strong as its integration points – A single innerHTML call can collapse an entire isolation model.
  • Third‑party libraries can unintentionally expose privileged APIs (MathLive’s virtual keyboard).
  • CSP whitelists must be reviewed for reflection vectors; allowing domains like YouTube can enable script injection via oEmbed.
  • Bug bounty rewards should reflect the severity of account‑takeover bugs; the $5 000 payout was widely considered low.
  • Defensive coding practices – validate message origins, avoid innerHTML, and use SRI or nonces for script loading.

By treating every user‑generated artifact as potentially hostile and enforcing defense‑in‑depth at the browser level, we can keep LLM‑enhanced UIs both powerful and safe.

Was this useful?

Get new posts by email

One short email a week with what I wrote. No spam, unsubscribe in one click.

Sources

Drafted with AI assistance from the sources above, then reviewed and published by Ferdous Azad. Spotted an error? Let me know.

Comments

No comments yet. Start the conversation.

Leave a comment

First-time comments are reviewed before they appear. Be kind and on topic.

More in AI & LLMs

View all