CVE-2020-17091 - Microsoft Teams Desktop RCE via Missing Context Isolation
While testing Microsoft Teams Desktop applications, I discovered a critical vulnerability that allows an attacker to execute arbitrary code on a user’s machine by exploiting a missing security flag in Electron’s authentication window. This vulnerability, assigned CVE-2020-17091, enables Remote Code Execution (RCE) through a malicious Teams application that can bypass Electron’s security controls.
The Vulnerability #
The vulnerability exists in how Microsoft Teams Desktop handles authentication windows for user-developed tab applications. Normally, content from a user-developed tab application is confined to an iframe with proper security controls and sandboxing. However, when an application calls microsoftTeams.authentication.authenticate({, it creates a new window outside of the sandbox to a URL controlled by the attacker.
While this new authentication window does have the nodeIntegration flag set to false, it is missing the critical contextIsolation flag. According to Electron’s security documentation, context isolation is an Electron feature that allows developers to run code in preload scripts and in Electron APIs in a dedicated JavaScript context. In practice, this means that global objects like Array.prototype.push or JSON.parse cannot be modified by scripts running in the renderer process.
Without context isolation, user-controlled content can abuse global object prototypes to intercept and manipulate Electron’s internal function calls, leading to arbitrary code execution.
Affected Versions #
- Affected versions: Microsoft Teams Desktop 1.3.2 and earlier versions
- CVE:
- Status: Fixed in later versions (fix was progressively rolled out starting April 2019)
The vulnerability affects any Microsoft Teams Desktop installation where a user installs and interacts with a malicious Teams application.
How It Works #
The attack works by exploiting the missing contextIsolation flag in the authentication window:
- Application Installation: An attacker creates a malicious Teams application that calls
microsoftTeams.authentication.authenticate() - Window Creation: When the authentication method is called, Teams creates a new window outside the sandbox to a URL controlled by the attacker
- Missing Security Flag: This window has
nodeIntegration: falsebut lackscontextIsolation: true - Prototype Pollution: The attacker’s JavaScript can modify global object prototypes (like
Function.prototype.call) - Code Execution: When Electron’s internal code calls functions on these prototypes, the attacker’s malicious code intercepts and executes arbitrary commands
The key exploit code abuses Function.prototype.call to intercept calls to Electron’s process object:
Function.prototype.call= new Proxy(Function.prototype.call, {
apply: function(target, thisArg, argumentsList) {
var ret = Reflect.apply(target, thisArg, argumentsList);
if(argumentsList[0].pid){ // this is probably a process ref
argumentsList[0].mainModule.require('child_process').execSync('open /Applications/Calculator.app');
}
return ret
}
});
location.href="done.html"
There is an eventual call through the process.on('exit', event in Electron core that is called before page navigation. In this call, a callback event is handled with handler.call(self) where self is a reference to the process object. By intercepting Function.prototype.call, the attacker can detect when the process object is passed and use it to require Node.js modules and execute arbitrary commands.
A good explanation of this type of attack can be found in Masato Kinugawa’s presentation on Electron security.
Proof of Concept #
To demonstrate this vulnerability:
- Install the “App Studio” app in Microsoft Teams
- Click on “Manifest Editor”
- Click “Import an existing app”
- Install the exported app from: https://gist.github.com/matt-/1a6f29a8b233e2cd7c5228ca523e5bf1/raw/d61d4db640bcb5f13f3e36d3055dfd70be287ae5/TeamsPOC.zip
- Follow prompts to install the Tab application into a channel
- Click on the tab from the desktop application
The payload was written and tested on macOS but could easily be modified for Windows. The execution is happening in the internal Node process and can fork off any process or edit/read any file the current user has access to.
Code Repository #
All code is available in a gist at: https://gist.github.com/matt-/1a6f29a8b233e2cd7c5228ca523e5bf1#file-index-html
The Impact #
This vulnerability is particularly dangerous because:
- Full system compromise: An attacker can run arbitrary commands on the victim’s system, potentially leading to persistent access
- Credential theft: The attacker could exfiltrate sensitive authentication tokens stored on the system, including Microsoft credentials, SSH keys, or environment variables
- Data exfiltration: An attacker could steal sensitive files, code, or other private data stored on the victim’s system
- Lateral movement: The attacker could use the compromised system to move laterally within an organization’s network
The attack is especially insidious because it requires minimal user interaction. Simply installing and clicking on a Teams application tab is enough ofr it to execute. The user doesn’t need to explicitly execute any suspicious files; the vulnerability is triggered through normal Teams application interaction.
Disclosure Timeline #
The disclosure process for this vulnerability was lengthy and complex:
- Sep 01, 2018 - Reported to MSRC
- Sep 14, 2018 - Confirmation (Ask for Windows POC)
- Sep 18, 2018 - Sent Windows POC
- Nov 27, 2018 - Request for update / BBP Questions
- Dec 03, 2018 - Response (We will get back to you)
- Mar 25, 2019 - Request for update
- Mar 25, 2019 - All Desktop apps excluded from BBP. No issue update.
- Apr 16, 2019 - Rolling out fix, request for repro
- May 06, 2019 - Still reproducible / Suggested fix not in place
- May 07, 2019 - Suggested fix not being used. “would break too much”
- Jun 19, 2019 - The patch was a “progressive” rollout and only went to 10% of users
- Jun 20, 2019 - Reversed the feature flag
enableRemoteModuleFilteringV5out and sent update confirming that this would not fix the issue - Jun 20, 2019 - MSRC confirms and will pass the info along
- Jul 18, 2019 - New version and electron update breaks exact POC. Warned of incomplete fix. Request coordinated disclosure
- Aug 02, 2019 - New POC sent
- Aug 15, 2019 - They are working on a “more comprehensive fix”
- Aug 27, 2019 - Some changes to remote-require break POC, new POC sent
- Oct 14, 2019 - Request for update
- May 13, 2020 - MSRC Request reset
- May 20, 2020 - Slight fix to payload on 1.3.00.9271 and it is still exploitable
- October 27, 2020 - CVE-2020-17091 assigned
- Nov 16, 2020 - Issue closed and CVE published
Expected vs Observed Result #
Expected Result: All windows would use contextIsolation
Observed Result: contextIsolation is not used in authentication windows
The Fix #
The fix requires enabling contextIsolation for all windows, including authentication windows created by microsoftTeams.authentication.authenticate(). This ensures that global object prototypes cannot be modified by scripts running in the renderer process, preventing the prototype pollution attack that leads to code execution.
Microsoft implemented a fix that was progressively rolled out, though the initial fix attempt was incomplete and required multiple iterations to fully address the vulnerability.
Takeaways #
This vulnerability highlights several important security lessons:
Electron security best practices: When using Electron, it’s critical to follow all security recommendations, including enabling
contextIsolationfor all windows that load remote content, not just some windows.Defense in depth: Even with
nodeIntegration: false, other security flags likecontextIsolationare essential. Security is not a single checkbox but requires multiple layers of protection.Prototype pollution attacks: The ability to modify global object prototypes can lead to serious security vulnerabilities, especially in environments where untrusted code runs alongside system code.
Progressive rollouts and security: Security fixes should be applied comprehensively, not through progressive rollouts that leave users vulnerable. All users should receive security patches simultaneously.
Testing security fixes: When implementing security fixes, it’s important to test thoroughly and ensure the fix actually addresses the vulnerability, not just breaks a specific proof of concept.
The fact that this vulnerability existed for over two years from initial report to CVE assignment demonstrates the complexity of fixing security issues in large applications, but also highlights the importance of comprehensive security fixes rather than partial mitigations.