Skip to content

[Regression]: Trace Viewer postMessage origin check breaks true single-file report integrations #40960

@baev

Description

@baev

Last Good Version

1.59.1

First Bad Version

1.60.0 / builds containing #40548

Steps to reproduce

  1. Create an HTML report page on a different origin than https://trace.playwright.dev,
    or open it as a single-file/static report.

  2. Embed Trace Viewer:

    <iframe id="viewer" src="https://trace.playwright.dev/"></iframe>
  3. Load a Playwright trace archive as a Blob in the report page.

  4. Pass it to the viewer:

    viewer.contentWindow.postMessage(
    {
    method: "load",
    params: {
    trace: traceBlob,
    },
    },
    "https://trace.playwright.dev",
    );

This worked before #40548.

After the change, Trace Viewer ignores the message because:

event.origin !== window.location.origin

For report systems like Allure, the trace is already present in the generated report.
In true single-file mode, the report data and attachments are embedded into one HTML file,
so the integration naturally passes the trace as a Blob.

Expected behavior

There should be a supported way for third-party report systems to pass an already-available
trace Blob into Trace Viewer.

Ideally, this could still preserve the security improvement against unsolicited messages,
for example through an explicit opt-in:

https://trace.playwright.dev/?allowPostMessageOrigin=https://reports.example.com

or a nonce/token handshake:

https://trace.playwright.dev/?postMessageToken=...

where the posted message must include the same token.

Actual behavior

Trace Viewer now only accepts postMessage trace blobs from the same origin as the viewer.

This means report systems cannot embed the hosted/static Trace Viewer and pass a trace blob
unless the report and viewer are served from the exact same origin.

The workaround is to copy/bundle the entire Trace Viewer asset directory next to the report
and serve it from the same origin. That works for directory reports, but it prevents true
single-file HTML reports from supporting Playwright traces.

Inlining the Trace Viewer into the report HTML is not a practical workaround because the
current Trace Viewer architecture depends on a service worker. The service worker acts as
the viewer's local virtual backend for trace contexts, snapshots, and recorded resources.
Browsers require service workers to be registered from a real same-origin HTTP(S) script URL,
so the service worker cannot be registered from inline JavaScript, a data: URL, a blob: URL,
or a file:// single-file report.

Additional context

I understand the intent of #40548: preventing arbitrary third-party pages
from embedding trace.playwright.dev and pushing a Blob into it via postMessage.

However, if the concern is attacker-controlled trace ingestion, an equivalent path still
appears to exist through the supported ?trace= URL flow.

For example, an attacker can embed:

<iframe src="https://trace.playwright.dev/?trace=https://evil.example/malicious-trace.zip"></iframe>

and serve the trace with:

Access-Control-Allow-Origin: https://trace.playwright.dev

So the origin check blocks cross-origin postMessage Blob injection, but it does not prevent
trace.playwright.dev from processing attacker-controlled trace bytes. It only changes the
required delivery mechanism from "post a Blob" to "host a ZIP with CORS enabled".

This removes a useful integration mechanism for legitimate report systems while leaving the
URL-based attacker-controlled trace path available.

The existing service-worker-based Trace Viewer architecture also means integrators cannot
simply inline the viewer into their own single HTML artifact. Even if all viewer assets and
the trace archive are embedded into the report, the browser still requires sw.bundle.js to
exist as a real same-origin HTTP(S) script URL before the viewer can load contexts, snapshots,
and recorded resources. This makes true single-file HTML report support impossible without
forking/reworking the Trace Viewer resource-loading architecture.

Request:

Could Playwright provide a supported integration path for report systems that already have
the trace as a Blob?

Possible options:

  1. Allow explicit trusted embedder origins.
  2. Add a nonce/token-based postMessage handshake.
  3. Publish/support Trace Viewer as an embeddable package/API.
  4. Document the intended third-party report integration path after cross-origin postMessage rejection.

Environment

-

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions