RCE in Jitsi Meet Electron prior to 2.3.0 due to insecure use of shell.openExternal() (CVE-2020-25019)

RCE in Jitsi Meet Electron prior to 2.3.0 due to insecure use of shell.openExternal() (CVE-2020-25019)

Jitsi Meet is an open source video conferencing software that organizations can deploy on their own servers and that is frequently recommended as an alternative to proprietary solutions. Jitsi Meet Electron is the official desktop client implemented using Electron that can be used both with the official meet.jit.si server as well as any third-party instance.

For my bachelor’s thesis, I manually analysed a couple of popular Electron apps for security vulnerabilities. I discovered multiple vulnerabilities, including the remote code execution vulnerability in Jitsi Meet Electron described in this post. CVE-2020-25019 was assigned to this issue.

First, I scanned the apps with the help of a modified version of the great Electronegativity by Doyensec. The results from the scan revealed the following use of Electron’s shell.openExternal() function (code from here):

mainWindow.webContents.on('new-window', (event, url, frameName) => {
  const target = getPopupTarget(url, frameName);

  if (!target || target === 'browser') {
    event.preventDefault();
    shell.openExternal(url);
  }
});

This hooks the creation of new windows to instead pass the URL to shell.openExternal() unless a popup target other than browser is registered for the URL and frame name of the new window. These popup targets are however only used to handle windows that should always stay on top (see here) and are thus not a security check.

As mentioned before, the app can be used with third-party servers. As such, it is possible for an attacker to inject a malicious call to window.open() into the pages of their Jitsi Meet instance that will then allow them to pass arbitrary URLs to shell.openExternal() when a user uses their server with the app. I have already written another blog post that goes into the details of the security problems with shell.openExternal().

In the case of this app, the attack surface was somewhat limited insofar as the external server is loaded through an <iframe> and opening file: URLs was thus blocked. However, all the other protocols could still be used as discussed. For example, a smb: URL to a .desktop file on a remote server allowed for RCE on Xubuntu 20.04, as described in the other post. Below is a video demonstrating the exploit:

The attack surface was further extended by the recent introduction of a protocol handler that allows linking to rooms on external servers (using jitsi-meet://jitsi.attacker.tld/dangerous-room). An attacker could use a link like this to lead a user to use their server without having to set the server URL in the app preferences.

Additionally, the app exposed the shell.openExternal() function on the window object which could be accessed from the renderer process as context isolation is disabled. This was not a critical problem as the remote site is only loaded in an <iframe> and thus doesn’t have access to the app’s window object. However, if an attacker somehow managed to achieve XSS in the renderer process, they could use this to escalate it into RCE. As there were no uses of the exposed function in the code, I included a recommendation to remove it in my report.

I reported the vulnerability to the developers on June 28, 2020. I confirmed that it worked using the latest release of the app at that time, version 2.2.0. Props to the Jitsi developers who implemented a fix just a few days later, on June 30, 2020, by filtering the URLs that may be passed to shell.openExternal() to only allow HTTP(S) URLs (see the fix commit). The fix was released in version 2.3.0 on July 2, 2020.


Timeline