---
title: Validate cross-frame messages
description: >-
  Check the origin and the sender of every `postMessage` event before you act on
  it, and send sensitive messages only to an exact target origin.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/security/backend/validate-cross-frame-messages
  md: >-
    https://shopify.dev/docs/apps/build/security/backend/validate-cross-frame-messages.md
---

# Validate cross-frame messages

Check the origin and the sender of every `postMessage` event before you act on it, and send sensitive messages only to an exact target origin.

***

## Why

Embedded apps, theme editor previews, and checkout extensions talk across frames with `postMessage`. Any frame that can reach yours can send a message, and a loose origin check accepts a lookalike domain.

***

## How

```javascript
window.addEventListener('message', (event) => {
  if (event.origin !== EXPECTED_ORIGIN) return;
  if (event.source !== window.parent) return;


  // Validate the message shape and values before acting on it.
});
```

Compare origins with `===` against an exact expected value. The following look safe but aren't:

* `origin.includes('shopify.com')`, which matches `shopify.com.attacker.net`.
* `origin.startsWith('https://shopify')`, which matches `https://shopify-lookalike.net`.
* Checking the message contents and inferring the sender from them.
* Sending sensitive messages with `postMessage(data, '*')`, which delivers to whatever is currently in that frame.

The frame that your embedded app runs in needs protection too. [Set up iframe protection](https://shopify.dev/docs/apps/build/security/set-up-iframe-protection) so that only the authenticated shop's admin can frame your app.

***

## Verify

The app security checks confirm the iframe protection headers. No check covers `postMessage` handlers, so review each one for an exact origin comparison and a sender check.

***
