An attacker who can add a client secret or certificate to an existing Entra ID application inherits every permission that application already holds, and the new credential keeps working after the original foothold is closed. MITRE ATT&CK describes this as adding credentials to service principals and applications "in addition to existing legitimate credentials", and it was a signature of the SolarWinds-era intrusions into Microsoft 365 tenants. This guide shows how to detect it: which audit events record a new secret, certificate or federated credential, how to parse them, which combinations separate a planned rotation from persistence, how to tie the new key to the sign-ins that use it, and how to respond. It is for SOC analysts, detection engineers and Entra application administrators. Managing secrets and their expiry is covered in the Azure Entra Client Secrets Security Guide; this page is about catching the credential nobody planned.
Key takeaways
- Three audit operations carry the signal: "Update application - Certificates and secrets management" on the app registration, "Add service principal credentials" on the enterprise application, and "Add service principal" when a credential arrives with a new principal. Microsoft's own Sentinel rules match all three.
- The service principal path is the stealthy one: credentials added directly to a service principal often do not appear in the portal's Certificates and secrets blade, so only the audit log and a Graph sweep show them.
- Every credential has a key ID: the audit event's
KeyIdentifiermatchesServicePrincipalCredentialKeyIdin service principal sign-in logs, so you can prove whether the new key has been used, from where and against which resource. - Context decides severity: a credential added outside a change window, by someone who is not an owner, to an app with high-privilege permissions, or to an app that previously had no credential, is the alert. Planned rotations are not.
- Prevent the multi-tenant variant: app instance property lock stops credentials being added to your app's service principal in other tenants; Microsoft states it has been enabled by default for new applications since June 2026.
When you need this
- After any admin account compromise: an Application Administrator or Cloud Application Administrator can add credentials to almost any app. Adding one to an app that already holds
Mail.ReadorDirectory.ReadWrite.Allapplication permissions is faster and quieter than creating a new app. - Apps with owners outside IT: app owners, including non-admin members, can add passwords to apps they own. A compromised owner account is enough.
- Privileged automation identities: an application holding
Application.ReadWrite.OwnedByorApplication.ReadWrite.Allcan add credentials through Microsoft Graph, so one leaked secret can be used to mint more. - Vendor and SaaS integrations: the Commvault Metallic incident exposed Microsoft 365 app secrets held by a vendor; customers then had to know which credentials existed and whether they had been used. See the Commvault Metallic Breach 2025.
Before you start
| Credential type | Stored on | Audit operation (Core Directory, ApplicationManagement) | How it shows in sign-ins |
|---|---|---|---|
| Client secret on app registration | application.passwordCredentials | "Update application - Certificates and secrets management" | ClientCredentialType client secret; ServicePrincipalCredentialKeyId |
| Certificate on app registration | application.keyCredentials (usage Verify) | Same | Client assertion; ServicePrincipalCredentialThumbprint |
| Secret or certificate on service principal | servicePrincipal.passwordCredentials or keyCredentials | "Add service principal credentials" | Same fields |
| Federated identity credential | Application federated credentials | Recorded as an application update; confirm the exact activity name with a test in your tenant | FederatedCredentialId |
- Collect: Entra audit logs (
AuditLogs) and service principal sign-ins (AADServicePrincipalSignInLogs) into the SIEM. Without the second table you can see a key being added but not whether it was used. - Read the property: credential details sit in
TargetResources[].modifiedPropertiesunder the display nameKeyDescription, with old and new values as lists of entries containingKeyIdentifier=,KeyType=,KeyUsage=andDisplayName=. - Test: add a secret and a certificate to a test app registration and a secret to a test service principal, then confirm all three events arrive and parse. Remove them afterwards and confirm the removals are logged too.
- Know your privileged apps: export application permissions (app role assignments) for every service principal so rules can raise severity for apps holding high-impact permissions. See How to find expiring app secrets and certificates in Entra ID for an export of every existing credential.
Step-by-step
- Filter the operations. Match
OperationNamecontaining "Certificates and secrets management" or "Add service principal" withResult == "success", as Microsoft's "New access credential added to Application or Service Principal" rule does. - Diff the key lists. Parse
KeyDescriptionold and new values and take the set difference, so a single event that lists every existing key yields only the new one. - Extract key ID, type, usage and display name. Keep
KeyUsageVerify (credentials used to authenticate the app); Sign is for SAML token signing and needs its own review. - Enrich with the initiating user or app, IP, user agent, the app's owners, its application permissions and whether a change ticket exists.
- Correlate with sign-ins: look up the new key ID in
ServicePrincipalCredentialKeyIdover the following days. - Run in report mode for two weeks, label each hit, then promote the High rules to paging.
A starting query, adapted from Microsoft's published Sentinel rule:
AuditLogs
| where OperationName has_any ("Add service principal", "Certificates and secrets management")
| where Result =~ "success"
| mv-apply T = TargetResources on (where T.type in~ ("Application", "ServicePrincipal")
| extend TargetName = tostring(T.displayName), TargetId = tostring(T.id),
TargetType = tostring(T.type), Props = T.modifiedProperties)
| mv-apply P = Props on (where P.displayName =~ "KeyDescription"
| extend NewKeys = parse_json(tostring(P.newValue)), OldKeys = parse_json(tostring(P.oldValue)))
| extend Added = set_difference(NewKeys, OldKeys)
| where array_length(Added) > 0
| mv-expand Added
| parse tostring(Added) with * "KeyIdentifier=" KeyId ",KeyType=" KeyType ",KeyUsage=" KeyUsage ",DisplayName=" KeyName "]" *
| extend Actor = coalesce(tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName)),
ActorIP = coalesce(tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress)),
FirstCredential = (tostring(OldKeys) == "[]")
| project TimeGenerated, OperationName, Actor, ActorIP, TargetType, TargetName, TargetId,
KeyId, KeyType, KeyUsage, KeyName, FirstCredential, CorrelationId
Microsoft's rules filter on application targets by default and note the filter can be widened to service principals; the version above includes both. Then join the output on KeyId to AADServicePrincipalSignInLogs on ServicePrincipalCredentialKeyId to list every sign-in made with the new credential. The KQL for Threat Hunting Guide explains the operators.
Detection rules
| Rule | Logic | Why it matters | Priority (ours) |
|---|---|---|---|
| First credential on an app | Old key list empty, new list has a Verify key (Microsoft ships this as High severity) | An app that never authenticated by itself suddenly can | High |
| Credential on a privileged app | Any new key on an app holding high-impact application permissions or directory roles | Directly inherits the most dangerous access | High |
| Credential on a service principal | "Add service principal credentials" outside a known automation identity | Hidden from the usual portal view | High |
| Actor is not an owner | Initiating user is not in the app's owners and not in the change-approved admin group | Admins adding keys to other teams' apps is rare | Medium |
| Added by an application | InitiatedBy is an app rather than a user | One app minting keys for another; legitimate only for known rotation tooling | Medium |
| After admin consent | Consent to the app followed by a credential added by a different actor (Microsoft rule "Credential added after admin consented to Application") | Turns a consented app into an attacker-held identity | Medium |
| Long or odd lifetime | endDateTime far beyond your policy (the Graph default is two years) or a display name that does not follow your convention | Credentials outside your policy deserve a second look even when planned | Low (enrichment) |
| New key used from new place | First sign-in with the new key ID from an IP or ASN the app has never used, or to a new resource | Confirms the credential is in use elsewhere | High |
| Burst | Credentials added to several apps by one actor within an hour | Scripted persistence across many identities | High |
Sweep existing credentials
Rules only see new events within your log retention. Credentials added before that are still valid.
- Export
passwordCredentialsandkeyCredentialsfrom every application and every service principal with Microsoft Graph, keepingkeyId,displayName,startDateTimeandendDateTime. Thehintfield holds the first three characters of a secret and helps match it to a stored value without exposing it. - Flag credentials on service principals of apps registered in your own tenant (usually unnecessary), credentials whose start date falls in a period of known compromise, and apps with more credentials than their owners can explain.
- Join each
keyIdto the last 30 to 90 days of service principal sign-ins. A credential that is used but that nobody claims is an incident; one that is unused is a removal candidate. - Ask each owner to confirm every credential. Owners who cannot are a governance finding in their own right.
Triage a hit
- Was it planned? Check the change ticket and ask the app owner through a channel the actor cannot see.
- Who added it? Review the actor's sign-ins in the hours before: risky sign-in, new location, MFA method change or role activation. See How to Detect MFA Method Registration Abuse.
- Has it been used? Sign-ins with the key ID, their IPs, resources and results.
- What can the app reach? Application permissions, directory roles, Azure RBAC assignments and mailbox access policies.
- What else changed? New owners, new permissions, redirect URI changes or consents on the same app in the same window. See How to detect OAuth consent phishing in Entra ID.
Respond to a rogue credential
- Preserve: export the audit entries, the app and service principal objects and the related sign-ins.
- Remove the credential by key ID from the application or service principal (portal for app registrations; Graph removePassword or removeKey, or the matching PowerShell cmdlets, for service principal credentials).
- Contain the app if it was used: disable the service principal while you investigate, and review what it accessed through the resource logs for each resource in its sign-ins.
- Contain the actor: revoke sessions, reset credentials and remove unexpected app ownership or admin roles from the account that added the key.
- Rotate the legitimate credentials on the same app if there is any chance they were read. See How to rotate Entra app secrets without downtime.
- Hunt across the tenant for the same actor, IP or user agent adding keys elsewhere.
Rollback: if the credential turns out to be legitimate and was removed, the owner issues a new one through the normal change process; never restore the removed secret, and record the key ID so the rule can suppress that rotation pattern.
Reduce the attack surface
| Control | What it does | Fits |
|---|---|---|
| App instance property lock | Blocks changes to Verify and Sign credentials and TokenEncryptionKeyId on the app's service principal in other tenants (App registrations, Authentication, App instance property lock) | Every multi-tenant app; check older apps created before the June 2026 default |
| Fewer application administrators | Limit Application Administrator and Cloud Application Administrator, and make them eligible through PIM rather than permanent | All tenants |
| Owner hygiene | Remove stale and personal owners; owners can add credentials to their apps | All tenants |
| Certificates or federation instead of secrets | Workload identity federation removes stored secrets entirely; certificates keep the private key on the client | Workloads in Azure, GitHub, Kubernetes and other supported issuers. See the Workload Identity Federation Guide |
| Credential policy | Restrict secret lifetimes and secret creation through Entra app management policies where licensed | Large tenants with many developer-owned apps |
- Small organisations: deploy the first-credential, privileged-app and service principal rules, run the sweep quarterly, and keep application administrator roles to two or three people.
- Large organisations: drive severity from an app criticality table, require change tickets for credentials on tier 0 apps, automate owner confirmation and run the sweep monthly.
Verify it worked
- Replay: add a secret to a test app holding a harmless application permission, sign in with it from an unusual network, and confirm both the credential rule and the "new key used from new place" rule fire.
- Removal: after response, re-list the app's credentials and confirm the key ID is gone and no sign-in with it has succeeded since.
Measures that show it is working
- Percentage of credential additions matched to a change ticket.
- Median time from credential addition to owner confirmation.
- Number of credentials on service principals of first-party apps, trending down.
- Number of apps still using client secrets rather than certificates or federation.
- Credentials found by the sweep with no owner confirmation.
Common failure patterns
- Watching only app registrations: the service principal path is where the stealthy credentials go.
- Alerting on every rotation: without change context the rule is muted within a week. Enrich, then alert on the exceptions.
- Not linking to sign-ins: without the key ID join, responders cannot say whether the credential was used, which drives the whole scope of the incident.
- Removing the key but not the actor: the admin account that added it will add another.
- Ignoring legacy apps: forgotten OAuth applications with broad permissions are ideal hosts for a new credential, as the Microsoft Midnight Blizzard intrusion showed. See the Microsoft Midnight Blizzard Breach 2024.
Framework mapping
| Framework | Reference | How this supports it |
|---|---|---|
| MITRE ATT&CK v20 | T1098.001 Additional Cloud Credentials; T1550.001 Application Access Token; T1078.004 Cloud Accounts | Detects credential persistence and its later use |
| NIST SP 800-53 Rev 5 | IA-5 Authenticator Management; AC-2 Account Management; AC-2(12) Account Monitoring for Atypical Usage; AU-6 Audit Record Review, Analysis, and Reporting; SI-4 System Monitoring | Controls and monitors authenticators issued to non-human identities |
| NIST CSF 2.0 | PR.AA-01; DE.CM-03; DE.AE-02 | Credential management for services, monitoring and analysis |
Practitioner checklist
- Stream Entra audit logs and service principal sign-in logs to the SIEM.
- Parse
KeyDescriptionand diff old and new key lists for applications and service principals. - Alert on first credentials, credentials on privileged apps and on service principals, and bursts.
- Join new key IDs to
ServicePrincipalCredentialKeyIdand alert on first use from new networks. - Sweep all existing credentials and get owner confirmation for each.
- Respond in order: preserve, remove the key, contain the app, contain the actor, rotate, hunt.
- Enable app instance property lock on multi-tenant apps and reduce application administrators.
- Move workloads from secrets to certificates or workload identity federation.
Standards and references
- MITRE ATT&CK: Account Manipulation: Additional Cloud Credentials (T1098.001)
- Microsoft: Azure Sentinel Microsoft Entra ID analytic rules
- Microsoft Learn: AADServicePrincipalSignInLogs table reference
- Microsoft Learn: Configure app instance property lock
- Microsoft Learn: application addPassword (Microsoft Graph)
- Microsoft Learn: passwordCredential resource type (Microsoft Graph)
Related NHI Mgmt Group resources: Azure Entra Client Secrets Security Guide · How to audit Entra workload identity federated credentials · Entra ID Sign-In and Audit Log Detection Guide · MITRE ATT&CK T1098 Account Manipulation Guide