javascriptarraysprototype-chain

How to reset broken JavaScript Array Object from new iframe?


I have a script which runs in a site that I cannot count on its window.Array object to not have been overridden. (It might have been changed by another script that was loaded before).

I create a new iframe and I would like to set the window.Array object back to the native Array prototype

    // let's assume Array.prototype.filter function was changed by another script
    Array.prototype.filter = ()=>{return "haha!"}

    console.log('test overridden: ', new Array(1,2,3).filter(x=>x));
    console.log('test overridden literal:', [1,2,3].filter(x=>x));

    // prints test overridden: haha
    // prints test overridden literal: haha

    // get new window with native code from iframe
    var iframe = null;
    (iframe = document.createElement('iframe')).name = 'native_function';
    document.body.appendChild(iframe);
    var native = window.frames['native_function'];

    // here I am trying to set my broken Array to a new fresh copy
    Object.setPrototypeOf(Array, native.Array.prototype);

    console.log('test restored filter: ', new Array(1,2,3).filter(x=>x));
    console.log('test restored literal array filter', [1,2,3].filter(x=>x));

 
    // prints test restored filter: haha
    // prints test restored literal array filter: haha

    // It didn't work.

How can I restore my window.Array to the native.window.Array ?

Note I want to restore the entire Array object to the original Array in the iframe window. Not only the filter function which I just used as as example.


Solution

  • I want to restore the entire Array object to the original Array in the iframe window

    You cannot overwrite the builtin array prototype that's used when creating arrays from literals, so instead you need to overwrite the methods on that one.

    const iframe = document.body.appendChild(document.createElement("iframe"));
    const iframeArray = iframe.contentWindow.Array;
    document.body.removeChild(iframe);
    
    const nativeArrayProto = Object.getPrototypeOf([]);
    for (const p of ["constructor", "filter", "map", "slice", /* … */])
        nativeArrayProto[p] = iframeArray.prototype[p];
    Array = nativeArrayProto.constructor;
    Array.prototype = nativeArrayProto;