JSFiddle - React, Tailwind, and code Playground

by Graham Dixon

HTML

<meta http-equiv="Content-Security-Policy" content="default-src https:">

JavaScript

let iframe = document.createElement("iframe");

iframe.setAttribute("sandbox", 'allow-scripts allow-same-origin');
iframe.setAttribute("id", 'evil');
iframe.setAttribute("name", 'evil');
document.body.appendChild(iframe);
console.log(iframe, iframe.contentWindow)
iframe.contentWindow.document.write(`<script>window.addEventListener('message', function (e) {
    // You must verify that the origin of the message's sender matches your
    // expectations. In this case, we're only planning on accepting messages
    // from our own origin, so we can simply compare the message event's
    // origin to the location of this document. If we get a message from an
    // unexpected host, ignore the message entirely.
    if (e.origin !== (window.location.protocol + "//" + window.location.host))
      return;

    var mainWindow = e.source;
    var result = '';
    try {
      result = eval(e.data);
    } catch (e) {
      result = 'eval() threw an exception.';
    }
    console.log(e.origin);
    mainWindow.postMessage({res:result, origin:e.origin});
  });<\/script>`);

window.addEventListener('message', function(e, origin) {
  // Sandboxed iframes which lack the 'allow-same-origin'
  // header have "null" rather than a valid origin. This means you still
  // have to be careful about accepting data via the messaging API you
  // create. Check that source, and validate those inputs!
  if (e.origin === e.data.origin && e.source === iframe.contentWindow)
    alert('Result: ' + e.data.res);
});

function evaluate(code) {
  // Note that we're sending the message to "*", rather than some specific
  // origin. Sandboxed iframes which lack the 'allow-same-origin' header
  // don't have an origin which you can target: you'll have to send to any
  // origin, which might alow some esoteric attacks. Validate your output!
  iframe.contentWindow.postMessage(code, '*');
}

console.log(evaluate("1+2"), new Function("return 1 + 2")());