App registrations are of vital importance when you are integrating third party applications to your Microsoft cloud environment or want to automate some of the mundane tasks. They are extremely powerful and handy to use.

But with great power, also comes great risk. During Solarigate (the attack on Solarwinds in 2020), the attackers used an OAuth application to escalate privileges and exfiltrate data. While app registrations are not new (they have existed since the start of Office 365), a lot of administrators are not fully aware of their risks and how to handle them. During this blog post, we’ll provide you some background information and advise you on how to handle them.

App registration creation

By default, every user (even non-administrators) have the ability to create new app registrations in your Azure AD tenant. While users are not able to create applications with permissions that they do not have access to by default, it is recommend to change this default behavior. This will ensure that the IT team is fully aware of all app registrations within your environment.

By going into Azure AD > User Settings we can turn off the ability for users to register applications.

After this has been configured, only eligible administrators are able to create applications. This includes the following built-in Azure AD roles:

  • Global Administrator
  • Application Administrator
  • Cloud Application Administrator
  • Application Developer

Azure AD also supports the ability to create custom roles, which can be used to delegated permissions to administrators.

Certain administrator roles also have the possibility to provide ‘admin consent’. By providing admin consent to an application, you agree that the application in question can access all the data within your tenant, as configured within it’s API permissions. Admin consent is an extremely powerful feature and should be handled with care. By default only an Global Administrator or Privileged Role Administrator can provide admin consent to Microsoft Graph permissions (which includes permissions to email, files and Teams).

Application Owners

Besides the above mentioned administrator roles, it’s also possible that other users have permissions to certain applications. Non-admin users can receive the owner role for a specific application. Owners have full control over an application, which means they can execute the following tasks:

  • Configuring redirect/reply URLs (used for authentication)
  • Add permissions (but they are unable to provide admin consent)
  • Interact with client credentials (add/remove secrets and certificates)

An owner can be added to an application in two scenarios.

  • The user who created the application is automatically an owner
  • An owner can also be added manually

If you disabled the ability for end-users to create app registrations, only administrators will be owners by default. Using owners are a great way to delegate administrator access to a limited amount of applications. While owners don’t hold an administrator role, it’s important to treat these accounts as high privileged as they have full access to the applications they are owner for.

Application Permissions

The differences between delegated and application permissions are an important thing to understand. Both have their valid use cases in different scenarios, but the goal of this blog is to make you understand the danger of assigning application permissions without much thought. Application permissions are applicable tenant wide by default, which means they are never scoped to a subset by resources by default. This sounds great, but it’s really something you should consider.

A lot of larger corporations have one big tenant, which includes multiple operating companies that have their own IT department. Some of these IT departments might have the need to create some kind of automation within M365, such as reading emails from certain mailboxes. If they would receive application permissions, they can’t just read the emails of their mailboxes, but the mails of the entire tenant.

While some workloads support scoping application permissions to certain resources, support is really limited. At the moment only Exchange and Sharepoint (preview) support it.

Client certificates and secrets

When a user has access to an app registration, they have the ability to update client credentials. Updating client credentials means that they have the ability to add new or update/remove existing client secrets and certificates. If that application has high privileges assigned to it, that user is able to create a new client credential and authenticate as that application. By authenticating as an application, the user is escalating it’s privileges to that of the application.

Imagine an app registration that has the application permissions ‘Mail.ReadWrite’, which provides the ability to update all the emails throughout all the mailboxes within your tenant. Somebody without a Global Administrator or Privileged Role Administrator isn’t able to add these permissions, but if they fit into one of the following cases, they do have the option to update the client credentials:

  • Application administrator
  • Application Developer
  • Owner of the application

If such a user account is breached, the attacker is able to create a new secret, authenticate as the application and remove all the emails throughout all mailboxes within your organization. That’s why it’s really important to implement the following security controls:

  • Restrict application owners and make sure they are properly protected
  • Monitor the addition of new client credentials and report abuse

App Registration Logins

When a user log ins to an application with delegated permissions, these sign-ins show up inside of the regular Azure AD sign-in logs. When an application with application permissions authenticates to Azure AD (through a client secret or client certificate) these don’t show up in the user sign-in logs, but are available within the ‘Service Principal logs’ which are available through the Azure AD portal and exportable to Log Analytics for ingestion into Azure Sentinel.

These kinds of logs are just as important as regular sign-in logs as Service Principals (app registrations) have no support for Conditional Access or Multifactor authentication.

Oftentimes, secrets/certificates are either:

  • Created to never expire
  • Not treated as confidential and saved in plain text (either on the desktop of the administrator or in the source code)

Which leads to these credentials being easily leaked.

Monitoring these logs is equally important as monitoring user sign-in logs as app registrations often have high-level permissions (such as reading mail).


While app registrations are a really neat way of integrating other applications into Microsoft 365, it’s important to be aware of the pitfalls. More often than not, they are not treated as important as high-risk accounts such as Global Administrator, but recent attacks show that they are a current attack vector and should be monitored as close as possible.

How Senserva helps keep your environment safe

Senserva is a product focused on keeping your Azure AD environment secure and enables you to easily identify potential issues in your environment. The product contains multiple controls that can be used to audit the current app registrations within your environment and be alerted when new instances of these applications are created.

In order to retrieve a list of all current applications, we can use the following sample KQL query:

| where TimeGenerated > ago(3d)
| where ControlName_s == "ApplicationPermission"
| distinct ControlName_s, Description_s, Value_s, ObjectId_g, MitreControls_s 

Below is an example output, which lists all the permissions assigned to an application.

Because this data is inside your Log Analytics workspace, it’s really easy to query certain permissions. With the example below, you can search for applications that are assigned to ‘offline_access’ permission:

| where ControlName_s == "ApplicationPermission"
| extend values =parse_json(Value_s)
| mv-expand values
| where values.Tag == "ApplicationPermission"
| extend permissions=parse_json(values.Value).["$values"], AppName = parse_json(Value_s)[0].Value
| mv-expand permissions
| where permissions.RoleName startswith "Device.ReadWrite.All" and permissions.RoleType == "Application Permission"
| distinct tostring(AppName), ControlName_s, Description_s, ObjectId_g, MitreControls_s, tostring(permissions.RoleName)

These logs can be created to audit applications, create workbooks or enrich existing Azure Sentinel events.

About Thijs

Thijs is a Microsoft 365 enthusiast based in Belgium. He currently works at The Collective Consulting, a Microsoft cloud partner, where he focuses on Security, Endpoint Management and Automation within the wide M365 stack.

In January 2021, he has received the Microsoft MVP work for his community contributions, which include:

If you ever want to reach out to Thijs, you can connect with him through LinkedIn or Twitter.