Reputation: 19840
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
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