CodePark/ questions / Iframes, sandbox & postMessage
START PRACTICINGPRACTICE
Frontend question · Frontend security › Iframes, sandbox & postMessage

A login popup sends its result back to the app with postMessage. What's wrong with this code on each side, and how do you fix it?

// app.example: receives the login result
window.addEventListener("message", (event) => {
  const { token, redirect } = event.data;
  localStorage.setItem("token", token);
  location.href = redirect;
});

// popup on auth.example: sends the result back
window.opener.postMessage({ token, redirect: "/home" }, "*");

Neither side checks who is on the other end.

The receiver doesn't check event.origin. Any window that can reach yours can send a message. That includes a page that opened your app, or any frame inside it. An attacker can:

  • send their own token, which logs the victim into the attacker's account
  • send redirect: "javascript:...", which runs script in your origin (XSS)

Fix the receiver:

  • Check the origin exactly: if (event.origin !== "https://auth.example") return;
  • Check that event.source is the popup you opened.
  • Check the shape of event.data.
  • Allow only relative redirect paths that you validate.

The sender uses "*" as the target origin. "*" means "deliver to whatever page is there now". If the opener window has moved to an attacker's site, the attacker receives the token. Fix: pass the exact origin, postMessage(data, "https://app.example"). The browser then drops the message if a different origin is in that window.

In short: check the origin on receive, and name the origin on send.

  • The receiver must compare event.origin exactly with the expected origin.
  • Check event.source and the shape of the data before using it.
  • Never navigate to a URL from a message without validating it.
  • The sender must pass the exact target origin, never "*", when the data is sensitive.