☁️Azure Entra IDApplicationsPermissionsIdentity

Azure App Registrations: The Over-Privileged Applications Hiding in Your Tenant

Over-privileged app registrations with leaked client secrets give attackers full API access to mailboxes, files, and Azure resources. Learn how to audit and secure your app registrations.

ES
EtcSec Security Team
5 min read
Azure App Registrations: The Over-Privileged Applications Hiding in Your Tenant

What Are Azure App Registration Risks?

App registrations in Azure Entra ID allow applications to authenticate and access Microsoft Graph, Azure resources, and other APIs. They are the identity layer for every custom application, automation script, integration, and third-party SaaS tool connected to your Microsoft 365 environment.

App registrations accumulate over time just like user accounts. Shadow IT creates them without governance. Developers register apps for quick testing and never remove them. Third-party integrations request more permissions than needed. The result is an environment full of applications holding privileged access to mailboxes, SharePoint, Teams data, and Azure resources — often with credentials (client secrets) that never expire and no one monitors.

Compromising an app registration with high Microsoft Graph permissions is equivalent to compromising a privileged user account — often with fewer detection signals.


How It Works

App registrations authenticate to Entra ID using one of two methods:

  • Client secrets — passwords for the app, often with long expiry dates or no expiry
  • Certificates — X.509 certificates used for app authentication

Once authenticated, the app acts according to its API permissions. Two permission types exist:

  • Delegated permissions — app acts on behalf of a signed-in user
  • Application permissions — app acts as itself, without a user context

Application permissions are the dangerous ones. An app with Mail.ReadWrite application permission can read and write every mailbox in the tenant without any user interaction. An app with Directory.ReadWrite.All can modify any object in Entra ID — including creating new admin accounts.

When these permissions are granted to poorly secured or forgotten app registrations, attackers who obtain the client secret gain persistent, privileged API access to the entire tenant.


The Attack Chain

Step 1 - Enumerate App Registrations and Permissions

Connect-MgGraph -Scopes "Application.Read.All"

# List all app registrations with their permissions
Get-MgApplication | ForEach-Object {
    $app = $_
    $sp = Get-MgServicePrincipal -Filter "appId eq '$($app.AppId)'"
    $appRoles = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id

    [PSCustomObject]@{
        AppName    = $app.DisplayName
        AppId      = $app.AppId
        Created    = $app.CreatedDateTime
        SecretExpiry = ($app.PasswordCredentials | Sort-Object EndDateTime | Select-Object -Last 1).EndDateTime
        Permissions = ($appRoles.AppRoleId | ForEach-Object { $_.ToString() }) -join ", "
    }
} | Where-Object {$_.Permissions -ne ""}

Step 2 - Target Apps With High Permissions and Weak Secrets

Priority targets:

  • Apps with Mail.ReadWrite, Files.ReadWrite.All, or Directory.ReadWrite.All application permissions
  • Apps with client secrets expiring in years or never
  • Apps with secrets that have not been rotated in 12+ months

Step 3 - Extract or Brute-Force Client Secret

Client secrets are often stored insecurely — in code repositories, CI/CD pipelines, configuration files, or developer machines. Attackers scan GitHub and public repos for leaked Azure app credentials.

# Scan GitHub for leaked Azure client secrets
# Pattern: "client_secret" + Azure tenant domain in same file
# Tools: truffleHog, git-secrets, GitHub Advanced Security

Step 4 - Authenticate as the App and Exfiltrate

import msal

app = msal.ConfidentialClientApplication(
    client_id="APP_CLIENT_ID",
    client_credential="STOLEN_SECRET",
    authority="https://login.microsoftonline.com/TENANT_ID"
)
result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
token = result["access_token"]

# With Mail.ReadWrite.All — dump all mailboxes
import requests
r = requests.get("https://graph.microsoft.com/v1.0/users", headers={"Authorization": f"Bearer {token}"})

Detection

Microsoft Entra Audit Logs

EventWhat to Look For
Add applicationNew app registrations — especially outside change windows
Add password credentialNew client secret added to existing app
Add service principalNew enterprise app added to tenant
Consent to applicationUser or admin consent to third-party app permissions

SIEM Detection Query (Elastic KQL)

azure.auditlogs.operation_name: "Add password credential to service principal" AND
NOT azure.auditlogs.properties.initiated_by.user.roles: "*Admin*"
# Detect app authentication from unusual IPs
azure.signinlogs.properties.app_display_name: (* AND NOT "Microsoft*") AND
azure.signinlogs.properties.user_type: "servicePrincipal" AND
azure.signinlogs.properties.risk_level_during_sign_in: ("high" OR "medium")

💡 Tip: Enable Microsoft Graph activity logs and route them to your SIEM. App-based API access — especially bulk mailbox reads or user enumeration — is a strong data exfiltration indicator.


Remediation

💡 Quick Win: Run the PowerShell audit above and identify any app with Directory.ReadWrite.All or Mail.ReadWrite application permissions. Each one is a potential full-tenant compromise vector.

1. Audit and Remove Unused App Registrations

# Find apps with no sign-in activity in 90+ days
$cutoff = (Get-Date).AddDays(-90)
Get-MgApplication | Where-Object {$_.CreatedDateTime -lt $cutoff} | ForEach-Object {
    $sp = Get-MgServicePrincipal -Filter "appId eq '$($_.AppId)'"
    $lastSignIn = (Get-MgServicePrincipalSignInActivity -ServicePrincipalId $sp.Id).LastSignInDateTime
    if ($lastSignIn -lt $cutoff -or $lastSignIn -eq $null) {
        [PSCustomObject]@{App=$_.DisplayName; LastSignIn=$lastSignIn}
    }
}

2. Rotate Expiring and Old Client Secrets

# Find client secrets expiring within 30 days or already expired
Get-MgApplication | ForEach-Object {
    $_.PasswordCredentials | Where-Object {$_.EndDateTime -lt (Get-Date).AddDays(30)} |
        Select-Object @{N="App";E={$_.DisplayName}}, EndDateTime
}
# Rotate via: Add-MgApplicationPassword / Remove-MgApplicationPassword

3. Replace Secrets With Certificates

Client secrets are more easily leaked than certificates. Migrate high-privilege apps to certificate-based authentication:

# Generate a self-signed certificate
$cert = New-SelfSignedCertificate -Subject "CN=AppName" -CertStoreLocation "Cert:\CurrentUser\My" `
    -KeyExportPolicy Exportable -KeySpec Signature -NotAfter (Get-Date).AddYears(2)

# Upload certificate to app registration
$certData = [Convert]::ToBase64String($cert.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert))
$keyCredential = @{Type="AsymmetricX509Cert"; Usage="Verify"; Key=[Convert]::FromBase64String($certData)}
Update-MgApplication -ApplicationId $appId -KeyCredentials @($keyCredential)

4. Apply Least Privilege to App Permissions

Review every app registration and replace broad permissions with scoped alternatives:

  • Replace Mail.ReadWrite with Mail.Read if write is not needed
  • Replace Directory.ReadWrite.All with specific read permissions
  • Use delegated permissions instead of application permissions where user context is available

How EtcSec Detects This

EtcSec audits all app registrations and service principals in your Azure tenant.

The Applications category checks include: apps with overly broad application permissions (Directory.ReadWrite.All, Mail.ReadWrite.All, Files.ReadWrite.All), apps with expired or expiring client secrets, apps with no recent sign-in activity, and apps with admin consent granted to sensitive permissions without review.

ℹ️ Note: EtcSec audits all Azure app registrations and permissions automatically. Run a free audit to discover over-privileged and forgotten app registrations in your tenant.

Related articles: Azure Privileged Access | Azure Identity Security

EtcSec

© 2026 EtcSec. All rights reserved.

Azure App Registration Security: Permissions and Secrets | EtcSec — EtcSec Blog | EtcSec