◆ Acme Portal support origin … All scenarios
Hardened S5

Support widget — the same flow, done correctly

Identical traffic to /s1-widget, but every one of the four mistakes is gone. Run the S1 attacker page against this page and the payload is dropped before it reaches the DOM.

// 1. exact allowlist of origins we accept
const ALLOWED_ORIGINS = ["https://widget.pmlab.amir.baby"];
// 2. the one window we are allowed to hear from
const widgetFrame = document.getElementById("widget");
const ALLOWED_SOURCE = widgetFrame.contentWindow;

window.addEventListener("message", function (event) {
  // 3. who sent it?
  if (!ALLOWED_ORIGINS.includes(event.origin)) {
    console.log("Invalid origin!", event.origin);
    return;
  }
  // 4. which window sent it?
  if (event.source !== ALLOWED_SOURCE) {
    console.log("Invalid source!");
    return;
  }
  // 5. is the payload the shape we expect?
  if (typeof event.data !== "string" || event.data.length > 200) {
    console.log("Unexpected payload!");
    return;
  }
  // 6. render it as TEXT, never as HTML
  document.getElementById("output").textContent = event.data;
});
window.parent.postMessage(message, "https://victim.pmlab.amir.baby");   // never "*"

What changed, and why each one matters

FixStops
Exact origin allowlistAny other origin, including subdomains of a trusted domain
event.source checkAnother window of the same origin (e.g. an unrelated tab) impersonating the widget
Payload shape checkObjects, arrays and oversized strings reaching the sink
textContent sinkHTML injection, even if every check above were bypassed
Explicit target origin on sendThe message reaching a window that was never meant to have it
Defence in depth. Any one of the last three rows would have stopped the writeup's exploit on its own. The origin allowlist is the primary control; the safe sink is the one that holds when the primary control is wrong.

Widget output

Raw payload received

—

Embedded widget

Served from https://widget.pmlab.amir.baby — the only origin accepted.

Message flow