diff --git a/bundled-addons/aegis/wallet-inject.js b/bundled-addons/aegis/wallet-inject.js index 1a73782d..fbd8be1d 100644 --- a/bundled-addons/aegis/wallet-inject.js +++ b/bundled-addons/aegis/wallet-inject.js @@ -191,13 +191,20 @@ theseus.contextBridge.exposeInMainWorld("wizardconnect", wizardconnect); // to us via `window.postMessage` on a namespaced envelope. This mirrors how // MetaMask and Phantom bridge extension code back to page code. -// Namespace used on the postMessage envelope. Includes the addon id so a -// page that runs multiple dapp-wallet extensions doesn't misroute messages. -const AEGIS_TAG = "aegis-" + theseus.id; +// Namespace used on the postMessage envelope. Includes the addon id plus a +// per-page-load nonce: only the main-world bridge we install below knows +// it, so a cross-origin iframe on the page cannot address the relay. The +// listener additionally requires the event to come from this very window +// (e.source === window) — an iframe's postMessage to its parent has +// e.source === that iframe — so a request can never be attributed to the +// top-level origin by anything but the top-level page's own scripts. The +// old fixed tag let any embedded ad frame call the wallet as the page. +const AEGIS_TAG = "aegis-" + theseus.id + "-" + Array.from(crypto.getRandomValues(new Uint8Array(12)), (b) => b.toString(16).padStart(2, "0")).join(""); const pendingCalls = new Map(); window.addEventListener("message", async (e) => { - const d = e && e.data; - if (!d || d.aegisTag !== AEGIS_TAG) return; + if (!e || e.source !== window || e.origin !== location.origin) return; + const d = e.data; + if (!d || typeof d !== "object" || d.aegisTag !== AEGIS_TAG) return; if (d.kind === "request") { // Forward main-world → isolated-world → addon. try { @@ -229,8 +236,9 @@ const mainWorldSource = `(function () { }); } window.addEventListener("message", (e) => { - const d = e && e.data; - if (!d || d.aegisTag !== TAG) return; + if (!e || e.source !== window) return; + const d = e.data; + if (!d || typeof d !== "object" || d.aegisTag !== TAG) return; if (d.kind === "response") { const p = pending.get(d.id); if (!p) return;