In our continuous effort to help secure open-source projects and improve our Clean Code solution, we regularly scan open-source projects via SonarCloud and evaluate the findings. When scanning the popular C# Content Management System Squidex, we were faced with the following finding reported by SonarCloud:
SonarCloud detected that this event listener does not verify the event’s origin. This doesn’t feel like a big deal, does it?
As we will see in this blog post, it is a big deal and allows attackers to fully take over a vulnerable Squidex instance by tricking a user into clicking on a malicious link. The blog post will detail how attackers can leverage this seemingly minor issue of a missing origin check to achieve code execution and explain how you can discover similar issues in your own code.
Squidex version 7.8.2 and below is prone to Cross-Site Scripting (XSS) vulnerability via event listener (CVE-2023-46252). Attackers can combine this vulnerability with an authenticated Arbitrary File Write (CVE-2023-46253) to gain remote code execution (RCE) on a Squidex instance:
Both vulnerabilities were fixed with Squidex version 7.9.0.
In this section, we describe the technical details of both of these vulnerabilities.
Before we dive into the technical details of this vulnerability, let’s see how we were able to discover it within seconds. On SonarCloud, an application can quickly be analyzed by adding the corresponding GitHub repository. For public repositories, this is even free, regardless of their size or language. Once the repository is added, SonarCloud starts to analyze the code and we can inspect the findings a few seconds later:
Let’s have a look at the reported
eventListener function, which is registered in the
Although the event listener checks the source of the event (
event.source), it is indeed missing a check of its origin (
event.origin). Because of this as well as the lack of X-Frame-Options and Content-Security-Policy, a malicious website can include the Squidex website in an iframe and use the postMessage method to trigger the execution of the event listener in the context of the included Squidex website:
Looking at the different
type values attackers can submit this way, the
valueChanged type caught our attention. When the
SquidexFormField receives a message with this type, the
value property is updated and the function
raiseValueChanged is called:
raiseValueChanged function invokes the
valueHandler callback, which can be registered via 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 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, attackers can include the
When determining the impact of this vulnerability, we identified a second vulnerability. This vulnerability is an authenticated file write, which attackers can combine with the XSS vulnerability to execute arbitrary code.
Squidex allows users with the
squidex.admin.restore permission to create and restore backups. Part of these backups are uploaded assets. For each asset, the backup zip archive contains a
.asset file with the actual content of the asset as well as a related
AssetCreatedEventV2 event, which is stored in a JSON file (
Amongst other things, the JSON file contains the event type (
AssetCreatedEventV2), the ID of the asset (
46c05041-9588-4179-b5eb-ddfcd9463e1e), its original filename (
test.txt), and its file version (
When a backup with this event is restored, the corresponding asset needs to be re-created. This is done by:
- determining the name of the
.assetfile in the zip archive,
- reading its content, and
- storing the content in the filestore (by default
However, the filename used to store the content in the filestore is populated with the ID of the asset. Since this asset ID is taken from the provided JSON file, attackers can set this to an arbitrary value when restoring a backup. This allows attackers to insert a path traversal sequence (
../) and write the
.asset file from the backup zip archive to an arbitrary location on the file system.
The by-default appended file version, which is not a
string but a
long, would usually restrict the name of the written file. However, attackers can overcome this by setting the
-1, which makes the application omit the file version:
Thus attackers can fully control the name and the content of the file written. This ability can be turned into arbitrary code execution by, for example, overwriting the
dotnet-gcdump.dll file and triggering
gcdump via the
In summary, the seemingly minor issue of a missing origin check can be leveraged by attackers to craft a malicious link, which triggers an XSS attack to gain remote code execution via this additional arbitrary file write vulnerability.
The XSS vulnerability (CVE-2023-46252) was fixed by adding the missing origin verification. Since there are valid use cases for certain origins to send messages to a Squidex website, a dynamic configuration was introduced:
The arbitrary file write vulnerability (CVE-2023-46253) was fixed by preventing a path traversal attack. An additional check was added to the
FilePathHelper class, which ensures that files are only created within the intended destination folder:
|We report all issues to the maintainers.
|We ask the maintainers for an update.
|The maintainers confirm the issues.
|We help the maintainers to fix both issues.
|The maintainers release the patched version 7.9.0.
In this blog post, we outlined the importance of verifying an event’s origin. We have seen how the absence of a check like this can quickly result in a severe impact. For Squidex, attackers could leverage the missing check to craft a malicious link, which triggers an XSS attack to gain remote code execution via an additional arbitrary file write vulnerability.
From a developer’s point of view, a check like this can be easily forgotten because it needs to be consistently applied to all event listeners throughout the whole code base. That’s where our SAST-based Clean Code solution provides irreplaceable benefits. By leveraging the analysis power of SonarQube or SonarCloud you can ensure that your code stays consistent, intentional, adaptable, and responsible. You don’t even want to introduce issues in the first place? With SonarLint you can follow a Clean as You Code approach right from your IDE of choice.
At last, we would like to thank the Squidex maintainers for confirming our findings and working together with us on a patch to fix these. Thank you!
- pfSense Security: Sensing Code Vulnerabilities with SonarCloud
- Unzipping Dangers: OpenRefine Zip Slip Vulnerability
- Pimcore: One click, two security vulnerabilities
- OpenEMR - Remote Code Execution in your Healthcare System