Skip to content

Bookmarklet postMessage rejected by overly strict origin check (cross-origin by design) #135

@kraftbj

Description

@kraftbj

What's happening

When the bookmarklet runs on a page (e.g. ma.tt) and opens Press This in a popup with proxy/server-side scanning disabled, the popup loads but no scraped data ever arrives — title, content, images, embeds, and selection are all empty. With proxy enabled, the auto-scan masks the symptom partially, but the bookmarklet's own postMessage payload is silently dropped.

Repro

  1. Disable Direct Access Mode / proxy in Press This settings (or use any bookmarklet flow on a host where the auto-scan also fails — see below).
  2. Visit any third-party page, e.g. https://ma.tt/2026/04/theopensource/.
  3. Highlight some text and click the Press This bookmarklet.
  4. The popup opens to …/wp-admin/press-this.php?v=11&u=…&pm=1 but the editor stays empty — no title, no quote, no images, no embeds.

Root cause

src/App.js:256 rejects every postMessage whose origin doesn't match the popup's own origin:

async function handleMessage( event ) {
    if ( event.origin !== window.location.origin ) {
        return;
    }
    
}

The bookmarklet runs on whatever page the user is on (any third-party site), so event.origin is always something like https://ma.tt, never the WordPress site's origin. Every legitimate bookmarklet message gets dropped.

When it broke

PR #100 ("Fix bookmarklet on mobile browsers", commit a55f050, Apr 3). The change came in under the commit "Harden window.name fallback and postMessage listener — Add event.origin check on the postMessage listener and a 1 MB size cap before parsing window.name."

The intent (don't let arbitrary pages forge press-this-data messages) is right; the check is wrong for this transport because the bookmarklet is cross-origin by definition.

Proposed fix

Validate the message source instead of its origin: only accept messages from window.opener (the bookmarklet's window, which holds the only reference to the popup it spawned). Something like:

if ( ! window.opener || event.source !== window.opener ) {
    return;
}

That keeps the spoofing protection (random pages can't postMessage into this popup without being its opener) without rejecting the bookmarklet's legitimate cross-origin payload.

Worth adding a regression test for the postMessage path in tests/ so this doesn't silently regress again — the existing tests around #100 cover bookmarklet generation and window.name fallback but don't exercise the postMessage receive path end-to-end with a cross-origin sender.

Related observations (may be separate issues)

While debugging I also saw:

  • The server-side /press-this/v1/scrape endpoint surfaces a generic "The URL could not be retrieved" error when an upstream returns non-2xx. NYTimes (https://www.nytimes.com/live/...) returns 403 to the Press This/<version>; <home_url> user agent (DataDome). YouTube watch URLs also fail in some cases for me on a live site. Anti-bot pushback is largely external, but the UX could be friendlier (and a more browser-like UA might shake some loose).
  • Clicking a YouTube thumbnail in the Scraped Media panel inserts a core/embed block but no preview renders. Haven't fully root-caused — flagging in case it's related to the same content path.

Happy to send a PR for the postMessage fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions