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. Application permissions can only ever be consented to by an administrator, never by an end user. For Microsoft Graph application permissions specifically, Microsoft documents that only Privileged Role Administrator and Global Administrator can consent; Application Administrator and Cloud Application Administrator can consent to application permissions excluding Microsoft Graph. 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 -All | 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 | ForEach-Object { "$($_.ResourceDisplayName):$($_.AppRoleId)" }) -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. Service principals that hold Entra admin roles outright are a separate and often worse case, covered in service principal admin role over-privileged.
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 service principal credentials | New client secret or certificate added to a service principal |
| Update application - Certificates and secrets management | New credential added on the application object itself |
| Add app role assignment to service principal | New application permission granted to an 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. Microsoft also documents that these events are aggregated: sign-ins are grouped into a single row when the service principal name or ID, the status, the IP address, and the resource name or ID all match, so expand a row before concluding that an app signed in only once. Managed identity sign-ins are not in this log; they have their own. For the detection patterns that work on this log specifically, see Entra service principal sign-in anomaly detection.
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)
data_stream.dataset: "azure.auditlogs"
and azure.auditlogs.operation_name: "Add service principal credentials"
and event.outcome: "success"
Use the activity name exactly as Microsoft publishes it in the audit activity reference. A credential added on the application object is logged under a different activity, Update application - Certificates and secrets management, so a rule that watches only the service principal activity misses half the cases. 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
Start from age, but do not confuse age with disuse. The query below lists applications registered more than 90 days ago, which in a mature tenant is most of them. It produces a review candidate list, not a list of unused applications.
$cutoff = (Get-Date).AddDays(-90)
Get-MgApplication -All | Where-Object { $_.CreatedDateTime -lt $cutoff } |
Select-Object DisplayName, AppId, CreatedDateTime
The disuse signal is authentication, not creation date: check the service principal sign-in logs for the app, or the Service principal sign-in activity usage and insights report, which is still in preview at the time of writing. 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 -All | ForEach-Object {
$app = $_
$app.PasswordCredentials |
Where-Object { $_.EndDateTime -lt (Get-Date).AddDays(30) } |
Select-Object @{n='AppName';e={$app.DisplayName}}, DisplayName, 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
Microsoft publishes an explicit order of preference here, and it does not start with certificates. Use a managed identity whenever the workload runs on Azure: Microsoft calls it the most secure option and strongly recommends it. If the workload runs elsewhere on a platform that offers automated credential management, use workload identity federation instead. Only when neither is possible should you fall back to certificate credentials, stored in a key vault and issued by a trusted CA rather than self-signed.
Microsoft's guidance on secrets is blunt: "Don't use password credentials, also known as secrets." Secrets are convenient, and that is exactly why they end up copied across developer and operational tooling. Application management policies can also cap secret lifetimes or block their use outright.
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.
The 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. Each of those maps to a dedicated check: dangerous mail, file, directory and role permissions granted to an app; applications carrying multiple active secrets or no credential rotation; applications and service principals with no owner; tenant-wide consent grants; and service principals still holding stale credentials. The value is in the join, not in any single flag.
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
Primary References
- Microsoft Graph permissions overview
- Microsoft Graph permissions reference
- Permissions and consent in the Microsoft identity platform
- Service principal sign-in logs in Microsoft Entra ID
- Security best practices for application properties
- Delegate application management administrator permissions
- Microsoft Entra audit log activity reference
Explore the identity security pages that support this topic

