The Microsoft Power Apps Portal Data Leak Revisited: Are You Safe Now?

What happened

In late August 2021, a major data leak exposed where 38 million private records through Microsoft’s Power Apps portals, a powerful low-code tool that enables both professional and citizen developers to create external-facing applications. The misconfiguration was discovered by the research team at UpGuard and is now well-known as one of the most severe low-code security incidents to date. In this article, we set out to analyze the root cause behind this data leak, verify Microsoft’s mitigation effectiveness, and provide our own recommendations for users of the platform.   

How it happened

Power Apps portals are a powerful low-code tool that enables professional and citizen developers to create external-facing applications where users outside of their organizations can view content, authenticate using various providers, and interact with data usually stored in Microsoft Dataverse (previously known as Common Data Services). By creating an external-facing application, it is implied, of course, that anyone on the Internet can view the website. Power Apps portals offer granular control over the types of data exposed to each user. Data can be shared with everyone (or “Anonymous access”, using the Power Apps portals terminology), with authenticated usersor with authenticated users with specific security roles such as “admin” or “content creator”.

The August leak was due to a misconfiguration; anyone on the Internet could access data which should have been available only to authenticated Portal App portals users with specific permissions. Moreover, this was the default configuration, which made the blast radius even larger with impact on huge companies such as American Airlines, Microsoft, J.B. Hunt and governments of Indiana, Maryland and New York City.

Microsoft was quick to respond, and has claimed that the issue has now been mitigated. Changing the insecure default configuration. In this post, we will detail the steps we took to verify that the issue was indeed fully resolved, to understand the impact on existing applications and our final conclusions.

Root cause analysis

To perform a root cause analysis of this low-code security breach, we need to become familiar with a few Power Apps portals features.

  1. Lists – Power Apps portals define access to data via lists. These are views into the Microsoft Dataverse database where the portal stores its data.
  2. Table permissions – Makers can assign permissions for users to have access to those lists, including read, write and delete access. They can also decide whether to turn on Table permissions, which makes the content private, i.e. available only to authenticated users, instead of the default public, i.e. available to any Internet user.
  3. OData – Microsoft Dataverse supports the Open Data Protocol (OData), an industry standard that allows developers to build automated integrations with APIs using a rich query language. This capability is designed to be used by applications, not directly by users. For ease of integration, portal makers can enable OData support for Power Apps portals lists.

The root cause for this data leak was a combination of the insecure default for Table permissions, with the user enabling OData for the list.

By default, when a user created a new list, it was automatically created with Table permissions disabled:

Table permissions disabled

This meant that the list was tagged as available for public view. However, the content was not actually exposed without an API or UI view that presented this data to users or applications.

The second step is for users to enable OData, which is a very common configuration setting, since it is needed in order to integrate the portal with other applications and data in the organizational ecosystem.

OData feed enabled

The combined effect of these two seemingly unrelated configurations, is that the list’s data is now exposed publicly through an API to the entire Internet.

Say. for example, that we had a portal named myportal and a list is called mylist. Then every person on the internet could use their browers to go to https://myportal.powerappsportals.com/_odata and see all the lists available in myportal. After locating the list they would like to leak, they would go to https://myportal.powerappsportals.com/_odata/mylist and retrieve all contents contained in that list.

The most critical issue here is that ‘Table permissions’ was disabled by default. This raises the question: why was this even possible? Naturally, portals need to have a way to expose data publicly since that is one of its core features, but this could be accomplished by assigning roles and permissions to the anonymous user rather than disabling permissions altogether.

Verifying Microsoft’s Mitigation

Following the disclosure, Microsoft has announced changes to the default behaviour, enforcing Table permissions for all lists. There are, however, two questions left unanswered:

  1. Can users override the now-secure default and disable Table permissions manually? If not, is this enforced on the API as well?
  2. What about existing applications with Table permissions disabled? How would customers identify these? How would they mitigate the issue?

Following the public disclosure, Zenity has invested time and resources in making sure that the vulnerability was properly mitigated. In the following section, we share our findings and the answers to the questions raised above.

Let’s start with Question 1: Can users override the now-secure default?

When creating a new portal, we see that the default configuration has changed and Table permissions are now enabled. Trying to disable table permissions manually while having OData enabled results in an error, preventing us from saving the new portal:

A breaking change introduced by Microsoft

The user is prevented from setting an insecure setting by the UI. Is this enforced at the API level as well? The answer is – no, users can override the default and set an insecure configuration.

Using the Microsoft Dataverse Web API, we send a PATCH request to https://{env-domain-name}.api.crm{area}.dynamics.com/adx_entitylists({list-id})’ with the following JSON body content: 

API request body

This request successfully disables Table permissions. These changes are reflected in the UI as well:

Table permissions disabled

OData feed enabled

However, trying to retrieve the list content as shown under Root Cause Analysis fails with the following message:

API access to Power Apps portals

We have now answered question 2 as well: What about existing applications? The answer is that Microsoft has introduced a breaking change that blocks access to OData feeds when Table permissions are disabled, thus completely mitigating the issue.

This change is indeed mentioned on the lists page in Microsoft Docs:

Lists that have OData feeds enabled require appropriate table permissions setup for the feed on these lists to work. Hence, you must enable table permissions on a list that has OData feeds enabled.

Recommendations

Zenity’s research concludes that Microsoft fully mitigated the issue and that customers are now protected. Having said that, in the process of doing so, Microsoft introduced a breaking change to the behavior of portal APIs. Customer applications that rely on the OData API can potentially be broken. Customers need to assess the usage of OData APIs in their organization, and detect cases where OData was actively used when table permissions were disabled.

How to detect and mitigate potential issues: