Too Broad Message Posting

ID

javascript.too_broad_message_posting

Severity

high

Resource

Information Leak

Language

JavaScript

Tags

CWE:346, CWE:940, NIST.SP.800-53, OWASP:2021:A4, PCI-DSS:6.5.3

Description

HTML5 provides the functionality of post cross-document messages (Web Messaging), allowing message posting between windows. window.postMessage() safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.

This targetWindow.postMessage(msg, targetOrigin) method can lift the same-origin restriction, by providing a way to securely pass messages across domains, with an option to specify the allowed origin for the target.

Always provide a specific targetOrigin, not '*', if you know where the other window’s document should be located. Failing to provide a specific target could disclose data to a malicious site.

This detector registers a vulnerability when the target origin is overly permissive (using '*' for the targetOrigin) in a postMessage() call, or when the origin is not checked in the event handler registered by the addEventListener() on the target window.

Rationale

Normally, scripts on different pages are allowed to access each other if and only if the pages that executed them came from same origins (protocol, host and port).

The Window.postMessage() method safely enables cross-origin communication, and provides a controlled mechanism to send data cross-origin, in a secure way when properly used.

For sending messages, syntax is: otherWindow.postMessage(message, targetOrigin, [transfer]), where otherWindow is the window that will receive the message, and targetOrigin may contain the URL of the window that the message is being sent to, or either "*" (any domain, no restriction) or "/" (same domain as sender).

The receiver then registers a message event handler, where the sender origin could be checked using the MessageEvent.origin property. The MessageEvent.source contains the sender’s window, for two-way communications. The message itself is provided in the MessageEvent.data property (and should be considered by the receiver as untrusted input, unless the origin is checked and it is trusted). It is important to check the origin to ensure the message is intended for the intended receiver.

An overly permissive target origin can provide a malicious script to communicate with the window in an inappropriate way. Attackers can:

  • Intercept sensitive data: If postMessage() is used to send authentication tokens, user data, or API keys, an attacker-controlled site in an iframe could read and steal this information.

  • Trigger actions in the receiving context: If the receiving window executes actions based on the received messages, an attacker could perform unauthorized transactions, change security settings, or exfiltrate user data.

On the sender side, any target origin is allowed, which means that the message can be sent to an iframe on a different domain.

var o = window.frames[0];
// Vulnerable - too broad origin.
o.contentWindow.postMessage(message, '*');

On the receiver side, the message event handler should check the origin:

const TRUSTED_ORIGIN = 'https://trusted.com';

// Vulnerable - not checking the event origin
window.addEventListener('message', function(event) {
    // ... process the message
})

Remediation

To address this vulnerability:

  • On the sender side, never use a wildcard origin ('*') with postMessage. Specify the exact target origin you intend to communicate with.

var o = window.frames[0];
// Vulnerable - too broad origin.
o.contentWindow.postMessage(message, 'https://trusted.com');
  • On the receiver side, always check the event.origin in your message event handler to ensure the data is coming from a trusted source.

const TRUSTED_ORIGIN = 'https://trusted.com';

window.addEventListener('message', function(event) {
    if (event.origin !== TRUSTED_ORIGIN) {
        // Reject messages from unknown sources
        console.warn('Message from untrusted source:', event.origin);
        return;
    }
    // ... process the message
})

There are more secure and structured alternatives to the native cross-origin message API, such as Postmate or Comlink. For messaging across different browser tabs or iframes in the same domain, the built-in BroadcastChannel API can be more convenient.

Configuration

This detector does not need any configuration.

References