Offirmo
Offirmo

Reputation: 19840

How can an iframe remove its own sandboxing?

I'm using a same-origin iframe to load a foreign widget (tlk.io loaded through a cross-origin script). I'm trying to give the iframe/widget the lowest possible rights to isolate it from my app.

MDN gives the following warning:

Notes about sandboxing:

When the embedded document has the same origin as the embedding page, it is strongly discouraged to use both allow-scripts and allow-same-origin, as that lets the embedded document remove the sandbox attribute — making it no more secure than not using the sandbox attribute at all.

Firefox devtools show me this warning:

An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can remove its sandboxing.

My question is: in this situation (sandbox="allow-same-origin allow-scripts") how could an iframe remove its sanboxing? What js code would perform this?

From the iframe, I tried looking at window.opener but it's null. window.parent is not referring to the parent (EDIT: NOT TRUE, I was using devtools wrongly). I can't find references to the «iframe» from the iframe itself...

Upvotes: 8

Views: 10313

Answers (1)

Henry Ecker
Henry Ecker

Reputation: 35626

You open yourself up to DOM manipulation by the iframe.

With both of those sandbox attributes, there is nothing to stop the embedded frame from replacing itself with a new iframe. An iframe with whatever privilege's it wanted enabled.

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Bad Sandboxing</title>
  </head>
  <body>
    <p>This is here to space out iframe</p>
    <iframe
      src="malicious_child.html"
      sandbox="allow-same-origin allow-scripts"
      id="mountPoint"
    >
    </iframe>
    <p>This is here to space out iframe</p>
  </body>
</html>

malicious_child.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Child</title>
</head>
<body>
<script type="text/javascript">
    document.body.innerText = "Loaded into a frame.";

    let parent = window.parent;
    let oldIframe = parent.document.getElementById("mountPoint");
    if (oldIframe != null) {
        // Build a new iframe to replace the old one.
        let newIframe = parent.document.createElement("iframe");
        newIframe.setAttribute("src", "malicious_child.html");
        newIframe.setAttribute("id", "maliciousFrame");
        // Replace Old iFrame
        oldIframe.replaceWith(newIframe);
    } else {
        // When new frame is mounted you will see this alert
        alert(
            "This should not happen since the original iframe did not have 'allow-modals'."
        );
    }
</script>
</body>
</html>

Here's a Code Sanbox with this setup.

Upvotes: 3

Related Questions