PostMessages are widely used to send messages from one window to another. Over time, there have been many security implications in post messages as many modern applications use them, so it becomes a security risk if it is not implemented correctly.
This blog is targeted at the folks who want to deep dive into postMessage vulnerabilities but before reading this article, Knowledge of the Document object model (DOM) is necessary to understand this blog.
What you are Going to Learn From this Blog?
- We are going to discuss a little bit about the Same Origin Policy.
- What is a postMessage? Why is it used? Their syntax to define.
- How to identify whether postMessage is being used or not?
- We will discuss about postMessage() Vulnerabilities
- We will discuss about one scenario for exploiting postMessage() Vulnerabilities.
- Remediation
Same Origin Policy
Modern web browsers employ an important security mechanism known as the Same Origin Policy (SOP) that acts as a security boundary between web pages loaded from different origins
What are Origins here?
Origin is a portion of the URl consisting of a specific protocol(scheme), host, and port. Schemes are the HyperText Transfer Protocols (http://
& https://
). The host is the website (www.example.com or example.com). The port is a number code at the end of the host (FTP 21 or WWW 80). When no port is specified, the browser defaults to port 80. The endpoints (ex./abcde
) are not part of the origin. If scheme, hostname or port anything get’s changed, then it will be considered as a different origin.
- Comparing the origin of different URL’s with
https://example.com:8080/abcde
Why we Need SOP ?
This is what Mozilla doc says about SOP.
The same-origin policy restricts how a document or script loaded from one origin can interact with a resource from another origin. It is a critical security mechanism for isolating potentially malicious documents, reducing possible attack vectors.
It means that a server can restrict access to it’s data if the browser sends a request from a different origin than the server.
- Scripts can only make HTTP requests and process responses between hosts that reside within the same origin.
- Scripts can only read and write to frames that reside within the same origin.
But suppose there is one large integrated applications such as those offered by Google present a wide range of services, each shown via different URLs (e.g. webmail via https://mail.google.com and video sharing via https://youtube.com). Youtube.com
cannot access cookies set via mail.google.com
due to the Same Origin Policy. Because of these limitations, most sites use Cross-Origin Resource Sharing (CORS) to relax the SOP instead. CORS is a mechanism that protects the data of the server. It allows servers to explicitly specify a list of origins that are allowed to access its resources via the HTTP response header Access-Control-Allow-Origin
Introduction to postMessage()
Sometimes a web application needs to embed an iframe or open a new window, for example, a third party contact form on an application. Now when this happens, the origin of the parent and child windows is different. THE SAME ORIGIN Policy won’t allow them to communicate with each other, and this is where the JavaScript postmessage method comes into play.
postMessage() sends data locally between the Window objects and does not generate an HTTP request to send data. It is used for DOM-based communication.
- The method
window.postMessage()
is used by the application to allow cross-origin communication between different 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 method provides a way to circumvent the Same Origin Policy restrictions securely.

window.postMessage() method – Sending Window
The method window.postMessage() is used by the application to allow cross-origin communication between different window objects, Since using postMessage() requires the sender to obtain a reference to the receiver’s window, messages can be sent only between a window and its iframes or pop-ups. That’s because only windows that open each other will have a way to reference each other. For example, a window can use window.open to refer to a new window it opened.
Alternatively, it can use window.opener to reference the window that spawned the current window. It can use window.frames to reference embedded iframes, and window.parent to reference the parent window of the current iframe. This method provides a way to circumvent the Same Origin Policy restrictions securely. You can use it to send text-based messages to another window.
Syntax:
targetWindow.postMessage(message, targetOrigin, [transfer]);
targetWindow
: A reference to the window that will receive the message. Methods for obtaining such a reference include: window.open, window.opener, window.parent, window.frames, etc.message
: Data to be send to the other window.targetOrigin
: The origin of the targetWindow that is supposed to receive the message. If the origin of targetWindow does not match with the targetOrigin specified here then message won’t be send at all. This adds a layer of security to the postMessage() functionality. The targetOrigin can also be specified by“*”
which means that the targetWindow can have any origin. However, one needs to be pretty careful while using“*”
with sensitive data being passed in the functionality.transfer
(Optional): It is a sequence of Transferable objects that are transferred with the message.
window.addEventListener() method – Receiving Window
If a message is sent, there must be receiving window who handles the message by using an event handler that will be triggered when the receiving window receives a message.
Syntax:
window.addEventListener("message", function()=> {
//Whatever you want to do with message data...
}, false/true);
message
: It is data that is sent from the source window to the targetWindowfunction
: Describes the actions to be performed with the data received.false/true
at the end is optional useCapture parameter that tells if the event should be executed in the capturing or in the bubbling phase (False by default).
Understanding the Flow of Sending and Receiving postMessage
For example, we want to pass the following JSON blob located at a.example.com/userinfo
to b.example.com
:
{'username': 'dn0m1n8tor', 'secret_ID': 'sRrsvRIMHSDBHeqAnhfdfnFB668LDR9Y'}
a.example.com
can open b.example.com
and send a message to its window. The window.open() function opens the window of a particular URL and returns a reference to it:
var recipient_window = window.open("https://b.example.com", b_domain)
recipient_window.postMessage("{'username': 'dn0m1n8tor', 'secret_ID': 'sRrsvRIMHSDBHeqAnhfdfnFB668LDR9Y'}", "*");
At the same time, b.example.com
would set up an event listener to process the data it receives:
function parse_data(event) {
// Parse the data
}
window.addEventListener("message", parse_data);
As you can see, postMessage() does not bypass SOP directly but provides a way for pages of different origins to send data to each other.
Identifying the use of postMessage():
Detection of these vulnerabilities is not pretty straightforward. It requires knowledge and understanding of JavaScript to read the target application’s JavaScript to identify potential attack points. It is required to trace the execution flow to perform a successful attack.
To exploit the postMessage() vulnerabilities, first, it is required to know if the target application is using web messaging or not. If the target application uses web messaging, it is essential to identify the various listeners. There are several methods to do so, including:
- Searching for the keywords: Use the developer tool’s global search option to search for specific keywords such as postMessage(), addEventListener(“message, .on(“message” in the javascript files.
- Using MessPostage Browser Extension: Using this extension is an easy way to detect whenever an application usage postMessage() APIs. This also shows which messages were sent and where event listeners have been added.
- Using Developer Tools: The “Global Listener” feature present in the “Sources” pane of Developer tools can be used to identify the use of postMessage(). After opening the Global Listener, click on “messages” to view the message handlers.
- Using Posta: Posta is a tool for researching Cross-document Messaging communication. It allows you to track, explore and exploit
postMessage
vulnerabilities, and includes features such as replaying messages sent between windows within any attached browser. - Using PMHook: PMHook is a client-side JavaScript library designed to be used with TamperMonkey in the Chrome web browser. Executed immediately at page load, PMHook wraps the EventTarget.addEventListener method and logs any subsequent message event handers as they are added. The event handler functions themselves are also wrapped to log messages received by each handler.source : Introduction to postMessage() Vulnerabilities
JavaScript postMessage() Vulnerabilities
If postMessage() is not implemented properly then it may lead to security vulnerabilities such as
- Cross-Site Scripting (XSS) which we will discuss with example in this blog
- Sensitive Data Exposure or information disclosure is another issue related to postMessage() in which sometimes PII-related information, leaked tokens or credentials such as API keys are leaked.
- Due to weak implementation of regex, such as accepting the wildcards may also allow an attacker to perform exploits that are otherwise blocker due to certain domain/host-based restrictions.
Exploiting postMessage() using iframe
We will be looking at exploiting the postmessage() vulnerability in the following lab environment. Here is the lab link Vuln Nodejs App
Let’s understand the flow of application…
- You can see we have a
change password
functionality, and when we click on it, we get a child window asking forchange password
.
- Fill the
New password
&Confirm password
fields and click on Save.
3.If you see we get here a message on parent window thatPassword update Successfull!
- Let’s
sudo dig -in
more in the flow…- If you view the source code of Parent Window, you will see there is one
addEventListener
on the window object, which means that we are listening for the eventmessage
to be fired.message
event fires whenever a window receives a message, which in this case will be throughpostMessage()
method. Then we have define function to be executed whenever we receives a message which change the HTML content of an element withid="displayMessage"
- If you view the source code of
Child Window
You can see there are some XHR requests and responses code. When we enter our password in child window for updating, that request get performed and then server send 200 response code with some response text as Password update Successfull!
- We pass this response to the sendMessage function.
- You can see in the sendMessage function definition that the child page can send a message to the parent. It identifies the parent through the window.opener and sends a message through postMessage(), which has two arguments
text
: The data which we want to send to the parent window which in this case is thePassword update Successfull!
*
: The postMessage() method allows the sender to specify the receiver’s origin as a parameter. If the sender page doesn’t specify a target origin and uses a wildcard target origin instead, it becomes possible to leak information to other sites:
- If you view the source code of Parent Window, you will see there is one
- Till now, you all have got the flow of code. So one thing to notice here is that the parent window is listening for event but not verifying from which origin the message is coming.
- Vulnerable code
- This is Secure code because here, we are verifying the origin of the sender by checking it against an acceptable origin.
- Vulnerable code
- Let’s take advantage of this vulnerable code and exploit the vulnerability. We have to write our own exploit
Explanation of Code :
- We have created a submit button, and when someone clicks on it, an
exploit
function is called. - We have loaded our lab website in an
iframe
. exploit() function
- First we have declared a variable
payload
which contains malicious JavaScript payload (line no. 7) - The
contentWindow
property returns the Window object of an HTMLIFrameElement. You can use thisWindow
object to access the iframe’s document and its internal DOM. This attribute is read-only, but its properties can be manipulated like the globalWindow
object.(line no. 8) - Then we are sending the payload to iframe through postmessage (line no. 9)
- First we have declared a variable
Exploit Code in Action
- As you can see, our exploit is ready… So just click on
exploit
😈 - Our xss get’s triggered 😎
Remediation:
- If the application does not require communication such as receiving messages from other websites, it is advised to not utilize the event listeners for the message events unnecessarily.
- Do not utilize a wildcard (*) target origin, instead use the expected target origin with the postMessage(). It will protect against the attack trying to use a malicious website to steal sensitive information.
- Always verify the sender’s identity using the origin.
- Setting appropriate X-Frame-Options and Content-Security-Policy headers will prevent the page from being loaded in an iframe.
Conclusion:
I hope you have learned how postMessages vulnerability occurs, how you can take advantage of it and remediate it.