Theseus: credit a wiz:// pairing link only to the top document
will-navigate and the window-open handler routed every wiz:// link to the wallet with the top-level URL's origin, whichever frame raised it. An ad iframe on a trusted dapp could window.open() a pairing URI and the pairing prompt would name the trusted site; one click on Pair gave the attacker the wallet's xpubs and a standing signing channel. A link must now come from the main frame (navigation initiator, or for window.open the referrer's origin), and only on pages where the wallet is allowed by the inject policy.
This commit is contained in:
parent
77f90dfa64
commit
b292408cea
1 changed files with 33 additions and 4 deletions
37
main.js
37
main.js
|
|
@ -4015,7 +4015,15 @@ function createTab(initial, opts = {}) {
|
|||
// wallet and leaves the dapp exactly where it is.
|
||||
if (parsed.protocol === "wiz:") {
|
||||
e.preventDefault();
|
||||
routeWizUri(u, pageOriginOf(wc.getURL()), tab.id);
|
||||
// Only the top document speaks for the top origin. A cross-origin
|
||||
// iframe (an ad on a trusted dapp) could navigate _top to a wiz://
|
||||
// link and the pairing prompt would name the trusted site.
|
||||
const init = e.initiator;
|
||||
if (init && init.frameTreeNodeId !== wc.mainFrame.frameTreeNodeId) {
|
||||
console.log("[wiz] ignored a pairing link from a sub-frame");
|
||||
return;
|
||||
}
|
||||
routeWizUri(u, wc.getURL(), tab.id);
|
||||
return;
|
||||
}
|
||||
if (parsed.protocol === "bns:") return;
|
||||
|
|
@ -4063,11 +4071,24 @@ function createTab(initial, opts = {}) {
|
|||
if (choice === 1) e.preventDefault(); // Leave anyway -> override the beforeunload
|
||||
});
|
||||
// Links that open a new tab: target="_blank", window.open, Ctrl/middle-click.
|
||||
wc.setWindowOpenHandler(({ url, disposition }) => {
|
||||
wc.setWindowOpenHandler((details) => {
|
||||
const { url, disposition } = details;
|
||||
// target="_blank" on a wiz:// link lands here rather than will-navigate.
|
||||
// Route it to the wallet instead of opening a tab on an unloadable URL.
|
||||
if (url && /^wiz:/i.test(url)) {
|
||||
routeWizUri(url, pageOriginOf(wc.getURL()), tab.id);
|
||||
// The open handler does not say which frame called window.open, but
|
||||
// the referrer does: a link or window.open from the top document
|
||||
// carries the top origin. Anything else (a sub-frame, or a referrer
|
||||
// stripped with noreferrer) is not credited to the top site.
|
||||
let refOrigin = null;
|
||||
try { refOrigin = details.referrer && details.referrer.url ? new URL(details.referrer.url).origin : null; } catch {}
|
||||
let topOrigin = null;
|
||||
try { topOrigin = new URL(wc.getURL()).origin; } catch {}
|
||||
if (!refOrigin || refOrigin !== topOrigin) {
|
||||
console.log("[wiz] ignored a pairing window from another frame or without a referrer");
|
||||
return { action: "deny" };
|
||||
}
|
||||
routeWizUri(url, wc.getURL(), tab.id);
|
||||
return { action: "deny" };
|
||||
}
|
||||
const installId = installLinkId(url);
|
||||
|
|
@ -5703,10 +5724,18 @@ function pageOriginOf(url) {
|
|||
// The wallet still shows its own approval before anything is paired; all
|
||||
// this does is carry the URI across, tagged with the origin that offered it
|
||||
// so the approval can name the real site.
|
||||
function routeWizUri(uri, origin, tabId) {
|
||||
// `pageUrl` is the top document's URL; the pairing is credited to its origin
|
||||
// only if the wallet may be on that page at all (the same inject policy that
|
||||
// decides whether the page gets the wallet bridge).
|
||||
function routeWizUri(uri, pageUrl, tabId) {
|
||||
if (!addonHost) return false;
|
||||
const u = String(uri || "");
|
||||
if (!/^wiz:/i.test(u) || u.length > 4096) return false;
|
||||
const origin = pageOriginOf(pageUrl);
|
||||
if (!origin || !addonHost.pageAllowed("aegis", String(pageUrl || ""))) {
|
||||
console.log("[wiz] pairing link ignored: the wallet is not enabled on this page");
|
||||
return false;
|
||||
}
|
||||
const send = () => addonHost
|
||||
.dispatch("aegis", "wcConnectFromPage", { uri: u }, { from: "page", origin: origin || "unknown site", tabId })
|
||||
.catch((err) => console.log("[wiz] pairing failed:", err?.message || err));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue