Azure App Registrations are one of the easiest places for tenant privilege to become invisible. An app registration can look like an integration detail, but its service principal can hold Microsoft Graph application permissions, active credentials, and tenant-wide access paths that do not depend on a signed-in user.
What Are Azure App Registration Risks?
Azure App Registrations are the identity objects behind custom applications, automation, integrations, and many third-party SaaS connections in Microsoft Entra ID. They can authenticate to Microsoft Graph, Azure resources, and other protected APIs.
The risk appears when those applications keep more permission than they need, keep credentials longer than they should, or stay in the tenant long after the original owner stopped paying attention. In that state, the application behaves like a standing privileged identity with far less day-to-day human visibility than a user admin account.
A good review is not only about finding one dangerous permission. It is about proving which applications are active, which ones have high-privilege application access, who owns them, and how their credentials are governed.
How It Works
App registrations usually authenticate with one of two credential types:
- client secrets
- certificates
The application then acts according to the permissions granted to its corresponding service principal.
Two broad permission models matter:
- delegated permissions, where the app acts in a signed-in user context
- application permissions, where the app acts as itself with no user present
Microsoft Graph documentation is explicit about the difference: application permissions are app-only permissions used without a signed-in user. A daemon app or backend service can use them to call APIs as itself. If the app has a broad application permission, the blast radius is determined by that permission and the resource, not by an interactive user's current session.
The highest-risk cases are usually application permissions that grant broad tenant-wide data access or directory modification capability. If an attacker obtains the app credential, the attacker inherits whatever API power the app already holds.
Azure App Registrations: What Makes Them High Risk
The dangerous pattern is usually a combination, not a single checkbox:
- broad application permissions such as tenant-wide mailbox, file, or directory access
- credentials that are long-lived, weakly rotated, or copied into multiple places
- no clear owner for the app or its service principal
- no recent sign-in activity, suggesting the app may be abandoned but still trusted
- admin consent granted long ago with no recurring review
That is why permission review without ownership review is incomplete. An app with moderate permissions and no owner can still become a serious incident when the secret is leaked and nobody notices the sign-ins.
A second practical distinction matters as well: some apps are risky because they can write or administer, while others are risky because they can quietly read large amounts of tenant data. Both cases deserve review, even when the portal labels them as different permission sets.
Permission facts that change the risk
Do not treat every Graph permission as interchangeable. Microsoft documents that application permissions can operate without a signed-in user, and some permissions allow organization-wide access to the associated data. For example, a broad file, mail, directory, or application-management permission can be more damaging than a delegated permission that only works inside a constrained user session.
Application management permissions deserve special attention. Microsoft Graph's permissions reference warns that permissions capable of managing credentials can let an application act as other entities and use privileges granted to them. That is a different risk class from an app that only reads its own profile.
Admin consent is also part of the control boundary. Microsoft documents that application permissions generally require administrator consent. If the tenant does not have a recurring review of admin-consented applications, the effective access model can drift for years after the original project ended.
The Attack Chain
Step 1 - Enumerate App Registrations and Their Permissions
Connect-MgGraph -Scopes 'Application.Read.All'
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 - Prioritize the Most Sensitive Combinations
Focus first on applications that combine broad tenant permissions with stale credentials or unclear ownership.
A useful triage order is:
- applications with application permissions to Microsoft Graph or Exchange workloads
- applications with app-management or directory-management permissions
- service principals with active credentials but no recent sign-in evidence
- apps with multiple active secrets or certificates where no owner can explain why
- apps with admin consent but no current business owner
Step 3 - Recover the Credential
Client secrets are often exposed through code repositories, deployment pipelines, local configuration files, or copied operational notes. The problem is not that secrets theoretically leak. The problem is that many tenants still rely on long-lived secrets for high-value apps.
Step 4 - Authenticate as the App and Use the Granted Scope
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']
At that point, the attack path is determined by the permissions already granted to the app, not by any new admin exploit.
Detection
Entra Audit and Sign-In Signals
| Signal | What to Look For |
|---|---|
| Add application | New app registrations outside expected change windows |
| Add password credential | New client secret added to an existing app |
| Consent to application | New delegated or admin consent on sensitive permissions |
| Service principal sign-in | App authentication from unusual IPs, locations, or times |
Microsoft documents service principal sign-in logs separately from interactive and non-interactive user sign-ins. Those logs are important because app-only authentication does not involve a human user. Review service principal name or ID, status, IP address, resource, credential type, and time clustering.
Practical Review Questions
- which apps hold application permissions with tenant-wide reach
- which apps have multiple active secrets or old secrets that were never removed
- which apps have no recent sign-in but still retain privileged access
- which apps have no active owner or business sponsor
- which apps can manage applications, service principals, credentials, grants, or role assignments
SIEM Detection Query (Elastic KQL)
azure.auditlogs.operation_name: 'Add password credential to service principal'
That event becomes much more useful when you enrich it with the app owner, previous credential inventory, and the permission level of the affected service principal.
Detection logic that reduces false positives
A new secret on a low-privilege test app is not the same as a new secret on an app with Graph application permissions and no owner. Prioritize by joining audit activity with app inventory:
- current app permissions and consent status
- whether the app uses application permissions or delegated permissions
- credential count and expiry dates
- last service principal sign-in time
- owner count and whether owners are still active employees
- whether the source IP or workload changed from the historical baseline
Remediation
Quick win: inventory every application with broad application permissions and make the owner attest that the permission and the credential are still required.
1. Remove or Disable Unused Applications
$cutoff = (Get-Date).AddDays(-90)
Get-MgApplication | Where-Object { $_.CreatedDateTime -lt $cutoff }
Use activity, ownership, and dependency review together. If no one can explain why the app still exists, it should not keep standing access.
2. Rotate and Reduce Credentials
Get-MgApplication | ForEach-Object {
$_.PasswordCredentials |
Where-Object { $_.EndDateTime -lt (Get-Date).AddDays(30) } |
Select-Object EndDateTime
}
Rotate old secrets, remove superseded secrets, and avoid leaving multiple valid credentials active without a reason. If a credential was copied into code, pipelines, or documentation, treat rotation as only one step. The old storage path also needs cleanup.
3. Prefer Stronger Credential Management
For high-value apps, certificate-based authentication is usually easier to govern than scattered long-lived secrets copied across developer and operational tooling. Where possible, also evaluate managed identities or workload identity federation so the application does not depend on a static shared secret.
4. Reduce Permission Scope
Review whether the app really needs application permissions at all. Where possible:
- replace broad write permissions with narrower read or scoped permissions
- prefer delegated permissions when a real user context exists
- remove admin consent that is no longer justified by the workload
- avoid granting app-management permissions unless the workload truly manages apps
- document why each remaining application permission is required
5. Lock Down Who Can Create and Consent to Apps
Microsoft provides tenant settings and delegated roles to control who can register applications and who can consent to applications. Disable broad user app registration and user consent where the business does not need it, then assign explicit roles for the teams that do.
This is not only governance. It prevents the tenant from reintroducing the same problem after cleanup. If anyone can create apps and request broad permissions without a review path, privileged app sprawl will return.
Validate Before You Close the Finding
An app registration review is not complete when the portal looks cleaner. Validate the outcome against the actual tenant behavior.
- export the remaining high-risk apps, their owners, their active credentials, and their effective permissions
- confirm old secrets were removed, not just replaced while the previous credential stayed active
- verify the app still works after permission reduction or credential rotation
- confirm abandoned applications were actually disabled or deleted instead of being left as undocumented exceptions
- review service principal sign-in logs after the change to confirm no unexpected source IPs or resources remain
- re-check admin-consented permissions and confirm the list matches the application inventory
Also review the surrounding governance path: who can create apps, who can grant admin consent, and who must approve privileged application access. Without that control, the same pattern will return in the next project cycle.
How EtcSec Detects This
EtcSec makes app-registration findings useful by combining privilege, credential age, ownership gaps, and activity signals. A tenant usually does not fail because it has many applications. It fails because a small number of applications have broad permissions, weak credential hygiene, and no clear review path.
There is no exact vulnerability taxonomy type in the current catalogue for over-privileged app registrations, so the useful detection model is exposure-based: broad application permissions, credentials that remain valid, unclear ownership, and service principal activity that does not match the documented use case.
Related Reading
- Azure Tenant Hardening: Fix Insecure Default Settings
- Azure Privileged Access: Too Many Global Admins
- Azure Conditional Access: MFA Bypass With Stolen Passwords
- Azure Guest Accounts: The Forgotten Attack Surface in Your Tenant
- Azure Identity Protection: Blocking Leaked Credentials

