Headline
CVE-2023-46252: Cross-Site Scripting (XSS) via postMessage Handler
Squidex is an open source headless CMS and content management hub. Affected versions are missing origin verification in a postMessage handler which introduces a Cross-Site Scripting (XSS) vulnerability. The editor-sdk.js file defines three different class-like functions, which employ a global message event listener: SquidexSidebar, SquidexWidget, and SquidexFormField. The registered event listener takes some action based on the type of the received message. For example, when the SquidexFormField receives a message with the type valueChanged, the value property is updated. The SquidexFormField class is for example used in the editor-editorjs.html file, which can be accessed via the public wwwroot folder. It uses the onValueChanged method to register a callback function, which passes the value provided from the message event to the editor.render. Passing an attacker-controlled value to this function introduces a Cross-Site Scripting (XSS) vulnerability.
Summary
The missing origin verification in a postMessage handler introduces a Cross-Site Scripting (XSS) vulnerability.
Details
The editor-sdk.js file defines three different class-like functions, which employ a global message event listener: SquidexSidebar, SquidexWidget, and SquidexFormField.
function SquidexFormField() { // … window.addEventListener('message’, eventListener, false); }
The registered event listener takes some action based on the type of the received message. For example, when the SquidexFormField receives a message with the type valueChanged, the value property is updated, and the function raiseValueChanged is called:
function eventListener(event) {
if (event.source !== window) {
var type \= event.data.type;
console.log('Received Message: ' + type);
if (...) {
// ...
} else if (type \=== 'valueChanged') {
value \= event.data.value;
raiseValueChanged();
}
// ...
The raiseValueChanged function invokes the valueHandler callback function, if defined:
function raiseValueChanged() {
if (valueHandler) {
valueHandler(value);
}
}
This callback function can be registered via the onValueChanged function:
/\*\*
\* Register an function that is called whenever the value of the field has changed.
\*
\* @param {function} callback: The callback to invoke. Argument 1: Field value (any).
\*/
onValueChanged: function (callback) {
if (!isFunction(callback)) {
return;
}
valueHandler \= callback;
raiseValueChanged();
},
The SquidexFormField class is for example used in the editor-editorjs.html file, which can be accessed via the public wwwroot folder. It uses the onValueChanged method to register a callback function, which passes the value provided from the message event to the editor.render function:
<!DOCTYPE html> <html> … <script> var field = new SquidexFormField(); var editor = new EditorJS({ … onReady: function () { field.onValueChanged(function (value) { if (value) { editor.render(value); } }); … </script> </body> </html>
The editor.render function used here is part of the editorjs npm package. Passing an attacker-controlled value to this function introduces a Cross-Site Scripting (XSS) vulnerability. Since the registered message event listener in editor-sdk.js does not verify the origin of the received message, an attacker can include the editor-editorjs.html page in an iframe and send a message to it in order to trigger the XSS vulnerability.
Please note that this is just one example of turning this into an XSS vulnerability. The root cause of this vulnerability is the missing origin checks of the message event listeners.
Impact
The vulnerability allows an attacker to execute arbitrary JavaScript code in the context of a user authenticated to Squidex by tricking them into visiting a malicious website.