Wed. December 14, 2011 @ 6:24 pm

Javascript Eval: A lesser Evil?

The evilness of window.eval has been beaten to death. I’ll save you a recap, but the biggest drawback is its potential for XSS. However, there are still valid (though limited) uses of eval—mostly to parse JSON when native methods are not available.

Futzing around, I noticed that it possible to execute javascript without eval.

var div = document.createElement("div");
div.innerHTML = "<input onchange=\"alert('hi');\" />";
div.firstChild.onchange();

There isn’t much to gain from this. But if moved into an iframe and fire the onclick event rather than calling it directly, could it be possible to dereference the parent window? That might allow a more secure state for using our new “eval”.

The following does just this. The parent window is detached by first removing the iframe from the document. Afterward, window.top no longer references the parent window.

window.SECRET = "!"; // something to hide!
window.IFRAME = document.createElement("iframe");
document.lastChild.appendChild(IFRAME); 
var doc = IFRAME.contentWindow.document;
doc.open();
doc.write("<input onclick=\"" + 
    "var c = top.console; " + 
    "c.log('Secret: ' + top.SECRET); " + 
    "top.IFRAME.parentNode.removeChild(top.IFRAME); " +
    "c.log('Secret: ' + (top && top.SECRET ? top.SECRET : 'Whaa!')); " + 
    "\" />");
doc.close();
var input = doc.getElementsByTagName("input")[0];
if (doc.createEvent) {
    var event = doc.createEvent("MouseEvent");
    event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, 
        false, false, false, false, 0, null);
    input.dispatchEvent(event);
} else if (doc.fireEvent) {
    input.fireEvent("onclick");
}

Prints:

Secret: 1
Secret: Whaa!

Example

I’ve mocked up a simple test using this concept. Enter javascript below and run. Note: you won’t have access to any of the usual functions (alert, console, etc.).

Tested in IE, Chrome, and Firefox. (working out some of the kinks of this demo - bare with me :)