Skip to content

Restrict embedded editor postMessage to allowed origins using IFRAME_ALLOWED_ORIGINS#1676

Merged
jasoncoffman merged 2 commits intopinterest:masterfrom
jasoncoffman:fix/cross-origin-postmessage
Mar 20, 2026
Merged

Restrict embedded editor postMessage to allowed origins using IFRAME_ALLOWED_ORIGINS#1676
jasoncoffman merged 2 commits intopinterest:masterfrom
jasoncoffman:fix/cross-origin-postmessage

Conversation

@jasoncoffman
Copy link
Copy Markdown
Contributor

@jasoncoffman jasoncoffman commented Mar 18, 2026

Problem

The EmbeddedQueryPage accepts postMessage calls from any origin and uses '*' as the target
for outgoing messages. This means any page — not just the intended embedding host — can inject
queries into the editor via SET_QUERY, potentially leading to unauthorized or unintended query
execution.

Solution

Validate event.origin against the existing IFRAME_ALLOWED_ORIGINS server configuration before
processing incoming SET_QUERY messages. This reuses the same setting that already controls CSP
frame-ancestors, so deployers get postMessage protection automatically with zero additional
configuration.

Changes

  • New API endpoint (GET /utils/embedded/allowed_origins/): Exposes IFRAME_ALLOWED_ORIGINS
    to the frontend. Requires authentication but not admin access.
  • Origin validation in EmbeddedQueryPage: Incoming messages are checked against the allowed
    list. Messages from unlisted origins are silently dropped. Messages coming from the Querybook origin are permitted.
  • No interim security gap: The message listener and SEND_QUERY handshake are deferred until
    the allowed origins have loaded, so there is no window where unvalidated messages are accepted.
  • Updated docs: infra_config.mdx now notes the dual role of IFRAME_ALLOWED_ORIGINS.

Backward compatibility

When IFRAME_ALLOWED_ORIGINS is not configured (the default), the allowed list is empty and all
origins are accepted — identical to the current behavior. No action is required from existing
deployers.

Alternatives considered

  1. Move allowed origins into querybook_public_config.yaml so the frontend can read them at
    build time without an API call. Rejected because IFRAME_ALLOWED_ORIGINS already lives in
    querybook_config.yaml / env vars, and requiring deployers to also add it to the public config
    would break backward compatibility for existing setups.

  2. Duplicate the value in both querybook_config.yaml and querybook_public_config.yaml.
    Rejected because maintaining the same list in two places invites config drift, which is
    especially risky for a security-sensitive setting.

  3. Current approach — lightweight API endpoint: A single source of truth
    (IFRAME_ALLOWED_ORIGINS) is read at runtime by both the server (CSP headers) and the frontend
    (via the new endpoint). No new configuration keys, no duplication, fully backward compatible.

@jasoncoffman jasoncoffman force-pushed the fix/cross-origin-postmessage branch from fb0cafd to ce69e2f Compare March 19, 2026 02:07
@jasoncoffman jasoncoffman force-pushed the fix/cross-origin-postmessage branch from ce69e2f to ddb13ab Compare March 19, 2026 02:13
@jasoncoffman jasoncoffman marked this pull request as ready for review March 19, 2026 16:29
@jasoncoffman jasoncoffman requested a review from kgopal492 March 19, 2026 16:29
@jasoncoffman jasoncoffman merged commit 747e0bb into pinterest:master Mar 20, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants