Detection rules › Panther
Azure Service Principal Credentials Added
Detects when new credentials (client secrets or certificates) are added to Microsoft Entra ID service principals or applications. Service principals are identities used by applications, services, and automation tools to access Azure resources, and they authenticate using credentials such as client secrets or certificates. Adversaries who compromise administrative credentials may add rogue credentials to existing service principals to establish persistent access that bypasses multi-factor authentication (MFA) requirements, as service principal authentication uses client credentials rather than interactive user login.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence | T1098.001 Account Manipulation: Additional Cloud Credentials |
Rule body yaml
AnalysisType: rule
Filename: azure_service_principal_credentials_added.py
RuleID: "Azure.Audit.ServicePrincipalCredentialsAdded"
DisplayName: "Azure Service Principal Credentials Added"
Enabled: true
LogTypes:
- Azure.Audit
Severity: Medium
Description: >
Detects when new credentials (client secrets or certificates) are added to Microsoft Entra ID
service principals or applications. Service principals are identities used by applications, services,
and automation tools to access Azure resources, and they authenticate using credentials such as client
secrets or certificates. Adversaries who compromise administrative credentials may add rogue credentials
to existing service principals to establish persistent access that bypasses multi-factor authentication
(MFA) requirements, as service principal authentication uses client credentials rather than interactive
user login.
Reports:
MITRE ATT&CK:
- TA0003:T1098
- TA0003:T1098.001
Runbook: |
1. Query Azure.Audit logs for all operations performed by properties:initiatedBy:user:userPrincipalName in the 7 days before and after this credential addition to determine if this was part of a broader compromise campaign involving multiple service principal modifications or privilege escalations
2. Verify with the administrator whether this credential addition was authorized through your organization's change management process and review the credential type (client secret vs certificate), expiration date, and whether it aligns with standard security practices for the affected service principal
3. Query Azure sign-in logs and API access logs for authentication activity using the affected service principal (properties:targetResources:id) in the 24 hours after credential addition to identify any suspicious resource access, data exfiltration, or privilege abuse that may indicate the credential is being misused by an attacker
Reference: https://github.com/elastic/detection-rules/blob/main/rules/integrations/azure/persistence_entra_id_service_principal_credentials_added.toml
SummaryAttributes:
- properties:initiatedBy:user:userPrincipalName
- properties:targetResources:displayName
- properties:targetResources:type
Tests:
- Name: Add Service Principal Credentials
ExpectedResult: true
Log:
{
"time": "2025-01-15 09:30:20.123",
"resourceId": "/tenants/tenant-123/providers/Microsoft.aadiam",
"operationName": "Add service principal credentials",
"operationVersion": "1.0",
"category": "ApplicationManagement",
"tenantId": "tenant-123",
"resultSignature": "None",
"durationMs": 0,
"callerIpAddress": "2.2.2.2",
"correlationId": "sp-creds-001",
"Level": "4",
"properties":
{
"result": "success",
"operationName": "Add service principal credentials",
"activityDisplayName": "Add service principal credentials",
"activityDateTime": "2025-01-15T09:30:20.1234567Z",
"loggedByService": "Core Directory",
"operationType": "Update",
"initiatedBy":
{
"user":
{
"id": "admin-123",
"displayName": "IT Administrator",
"userPrincipalName": "frodo@lotr.com",
"ipAddress": "2.2.2.2",
},
},
"targetResources":
[
{
"id": "sp-app-456",
"displayName": "Production API Service",
"type": "ServicePrincipal",
"modifiedProperties":
[
{
"displayName": "KeyDescription",
"oldValue": null,
"newValue": "\"Client Secret for API Access\"",
},
{
"displayName": "KeyType",
"oldValue": null,
"newValue": "\"Password\"",
},
],
},
],
},
"p_event_time": "2025-01-15 09:30:20.123",
"p_log_type": "Azure.Audit",
}
- Name: Create Service Principal
ExpectedResult: false
Log:
{
"time": "2025-01-15 15:05:25.678",
"resourceId": "/tenants/tenant-ghi/providers/Microsoft.aadiam",
"operationName": "Add service principal",
"operationVersion": "1.0",
"category": "ApplicationManagement",
"tenantId": "tenant-ghi",
"resultSignature": "None",
"durationMs": 0,
"callerIpAddress": "192.0.2.250",
"correlationId": "sp-create-001",
"Level": "4",
"properties":
{
"result": "success",
"operationName": "Add service principal",
"activityDisplayName": "Add service principal",
"activityDateTime": "2025-01-15T15:05:25.6789012Z",
"loggedByService": "Core Directory",
"operationType": "Add",
"initiatedBy":
{
"user":
{
"id": "admin-cloud-456",
"displayName": "Cloud Administrator",
"userPrincipalName": "cloudadmin@company.com",
"ipAddress": "192.0.2.250",
},
},
"targetResources":
[
{
"id": "sp-new-789",
"displayName": "New Automation Service",
"type": "ServicePrincipal",
},
],
},
"p_event_time": "2025-01-15 15:05:25.678",
"p_log_type": "Azure.Audit",
}
Detection logic
Condition
operationName contains "add service principal credentials" or properties.activityDisplayName contains "add service principal credentials"
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
| Field | Kind | Values |
|---|---|---|
operationName | contains |
|
properties.activityDisplayName | contains |
|
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
tenantId | |
operation_name | operationName |
activity_display_name | properties.activityDisplayName |
category | |
result | properties.result |
actor_user | properties.initiatedBy.user.userPrincipalName |
initiator_user_id | properties.initiatedBy.user.id |
initiator_display_name | properties.initiatedBy.user.displayName |
source_ip | properties.initiatedBy.user.ipAddress |