Poor Practice, But Unlikely to Cause Problems

Another week, another Teams vulnerability reported by BleepingComputer.com. The rash of reports must be as welcome to Microsoft as flatulence in a spacesuit, but like last week’s report about the GIFshell proof-of-concept attack, this week’s revelation is unlikely to impact users in the wild.

In a nutshell, the report (suffering at times from a severe case of hyperbole) describes how security researchers from Vectra found “a severe security vulnerability” in the Teams desktop app. Threat actors could exploit the vulnerability to use OAuth2 access tokens with accounts with multi-factor authentication turned on. According to the report, the issue impacts the Windows, macOS, and Linux versions of the Teams client. Sounds serious. At least, until you peel back the onion.

Using Teams Access Tokens

Azure AD performs authentication using different mechanisms and issues an access token after someone successfully goes through whatever authentication processes are demanded by a tenant, including multi-factor authentication.

This is one of the reasons why organizations should make it difficult for attackers to compromise accounts by removing the use of basic authentication for connectivity (what Microsoft is doing right now for Exchange Online) wherever possible. You can block legacy email connectivity protocols without waiting for the Microsoft process to roll out by implementing an authentication policy to block protocols commonly exploited by attackers like IMAP4 and POP3.

The great advantage of an authentication policy is that it blocks attempts to connect before they get a chance to present credentials and go through the authentication process. In other words, if you don’t connect using a supported protocol, Azure AD never gets to see the connection.

Security is further improved by enabling multi-factor authentication for all accounts, with accounts holding Microsoft 365 administrative roles a special priority. According to Microsoft, enabling multi-factor authentication blocks 99.9% of account compromise attacks. Putting up the multi-factor authentication barriers is a security 101 initiative for Microsoft 365 tenant administrators.

Local Access Required

The reported exploit is only possible if the attacker has “local access on a system.” In other words, the workstation is compromised, and the attacker has free rein to browse its contents, including the Teams cache. The Vectra researchers only made the discovery when they had full access to a workstation and were looking for ways to remove Teams data for disabled accounts.

Vectra claim that the vulnerability would allow the attacker to steal access tokens and “get away with major internal damage” by “taking control of critical seats.” Well, I guess if the attacker can waltz into the executive suite and take over the CEO’s computer, they could browse the Teams cache on that workstation. Given that they have full control over the workstation, it might be easier for the attacker to find interesting data to impose that “major damage” by opening the CEO’s email client.

Teams Tokens Stored in Clear Text

It’s certainly true that Teams stores access tokens in clear text. I examined a text file in the AppData\Roaming\Microsoft\Teams\Local Storage\leveldb folder and found several access tokens there. Figure 1 shows details of one of the tokens.

Azure AD access token stored in clear text by Teams
Figure 1: Azure AD access token stored in clear text by Teams

To avoid file conflicts, the Teams desktop client was not active at the time, and some of the tokens had only recently expired. I restarted Teams and searched for “expiration” again and found that a live token was now present. Expiration timestamps are in Epoch Unix format, and I used this site to check them.

I input each token into https://jwt.ms/ and to make sure that Azure AD had issued the tokens. All were valid (Figure 2).

Validating an access token
Figure 2: Checking an access token

It’s not good to hear that Teams stores sensitive data in clear text. That shouldn’t be the case. It’s kind of in the same category as an administrator writing down passwords and storing them in a text file on their PC. It’s certainly not beyond the wit of Microsoft to protect credentials, even for an Electron app (some commentators have pointed to the fact that Teams is an Electron app as a potential root cause for the problem).

Anyway, if the attacker declines to exploit the email and documents available on the workstation they’ve just compromised, they can fire up an SQLite client to read the cookies database (AppData\Roaming\Microsoft\Teams\Cookies – Figure 3) and retrieve the access tokens, which are also stored there in clear text.

Properties of the cookies database
Figure 3: Properties of the cookies database

Proof that Tokens Work

The proof of the exploit is to send a Teams chat message to the account (chat with self) using a Graph API, probably using the Teams Send chatmessage API using delegate permission. I don’t know if this is the case because Vectra’s blog post only includes the payload for the chat.

One thing that interests me is the assertion that the access token Vectra retrieved from the cookie database was still valid (and could be used with the Graph API request). Most of the tokens I saw had expired and a valid token was only present when the Teams client was active (and signed into the user’s account).

Revoking Access Tokens

When running, the Teams desktop client requests Azure AD to refresh its access token hourly (this is easily proved by examining the sign-in events in the Office 365 audit log). It’s also the case that Azure AD revokes access tokens when critical events such as when an administrator resets an account password, which you’d expect to happen when an administrator disables an account. The Microsoft 365 admin center also includes an option (Figure 4) to sign an account out of all sessions (this action revokes all current access tokens). It’s also something that should happen when an administrator disables an account.

The options to sign out Azure AD accounts from all sessions and block future sign-ins
Figure 4: The options to sign out Azure AD accounts from all sessions and block future sign-ins

I don’t doubt that the Vectra team was able to send a Teams chat message. What’s bothering me is how the access token was still valid. It could be that they were running the Teams desktop client at the time (this certainly happened to get the screenshot of the sent message).

Practical Next Steps

It’s certainly poor practice for Microsoft to store access tokens in clear text. I suspect that this has been the case since the first days of Teams and that no one has ever questioned the need for better security. Maybe this exposure will cause Microsoft to improve the situation, perhaps in the much-awaiting Teams 2.0 client for enterprise.

Vectra labeling this issue as “The Big Scary –The Ultimate Phish” is pure click-bait and I’m not worried about what they found.

First, it’s only after they gain access to a workstation that attackers can go looking for access tokens. Believe me, if an attacker controls a workstation, then being able to retrieve an access token is probably a long way down the list of nefarious actions they could perform on that system. The picture painted by Vectra when they say “with enough compromised machines, attackers can orchestrate communications within an organization” is unlikely in my judgment. In a scenario where “enough” systems are compromised, you’re in a world of hurt and probably aren’t worried about Teams messaging.

Second, methods exist to block attackers from being able to compromise accounts and being able to get into workstations. Use of modern authentication with multi-factor authentication makes the chances of penetration much less likely.

Third, an easy way exists to prevent access tokens issued to disabled accounts being valid: Revoke the tokens when you disable an account. This is good housekeeping and should always happen.

Follow Vectra’s recommendation to use the Teams browser client rather than the desktop client if you must, but I won’t. The exploit is implausible and impractical, and it would be nice if websites applied some critical thinking when they covered discoveries by security researchers to ask if an exploit could happen in the real world. Unfortunately, that seldom happens.

On Demand Migration

Migrate all your workloads and Active Directory with one comprehensive Office 365 tenant-to-tenant migration solution.

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.


  1. M

    It seems that this has been finally fixed in one of recent releases. Part of the file with the token now additionally includes “isEncrypted” property, and token itself indeed looks encrypted, as it’s not a valid JWT anymore.

  2. Stephan

    Is there any way to find out the latest status on this vulnerability?
    Has Microsoft already fixed it in the Teams Client?

    1. Avatar photo
      Tony Redmond

      Microsoft doesn’t regard the problem as being a security issue because the PC must already be compromised before the access token can be obtained. If you have an issue with this, complain to your local Microsoft office.

Leave a Reply