Entra ID ROPC Authentication with Unknown Client ID

Identifies potential OAuth client ID spoofing in Microsoft Entra ID sign-in logs. Adversaries submit fabricated or non-existent application identifiers (client IDs) in Resource Owner Password Credentials (ROPC) authentication requests to the token endpoint. Because Entra ID validates the submitted credential before rejecting the request on application resolution, the resulting error code acts as a credential- and account-validity oracle while never producing a successful sign-in. By fragmenting attempts across many fictional application identifiers, adversaries evade per-application detections, rate limiting, and application-scoped Conditional Access. This rule detects a ROPC authentication that fails with error code 700016 (application not found in the directory) where no application display name resolves, which is characteristic of a spoofed client ID used for stealthy user enumeration and password spraying.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/07/15"
  3integration = ["azure"]
  4maturity = "production"
  5updated_date = "2026/07/15"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Identifies potential OAuth client ID spoofing in Microsoft Entra ID sign-in logs. Adversaries submit fabricated or
 11non-existent application identifiers (client IDs) in Resource Owner Password Credentials (ROPC) authentication requests
 12to the token endpoint. Because Entra ID validates the submitted credential before rejecting the request on application
 13resolution, the resulting error code acts as a credential- and account-validity oracle while never producing a
 14successful sign-in. By fragmenting attempts across many fictional application identifiers, adversaries evade
 15per-application detections, rate limiting, and application-scoped Conditional Access. This rule detects a ROPC
 16authentication that fails with error code 700016 (application not found in the directory) where no application display
 17name resolves, which is characteristic of a spoofed client ID used for stealthy user enumeration and password spraying.
 18"""
 19false_positives = [
 20    """
 21    A legitimate application that has been deleted from the tenant while a client continues to authenticate against its
 22    former client ID via ROPC can generate error code 700016. A misconfigured legacy client submitting an incorrect
 23    client ID is also possible. In both cases the client ID is typically stable and low-volume, unlike the many distinct
 24    or randomized identifiers seen in spoofing. Verify the application identifier, the source infrastructure, and
 25    whether the same principal is targeted by many different unresolved client IDs.
 26    """,
 27]
 28from = "now-9m"
 29index = ["logs-azure.signinlogs-*"]
 30language = "kuery"
 31license = "Elastic License v2"
 32name = "Entra ID ROPC Authentication with Unknown Client ID"
 33note = """## Triage and analysis
 34
 35### Investigating Entra ID ROPC Authentication with Unknown Client ID
 36
 37Adversaries submit fabricated application identifiers (client IDs) in ROPC authentication requests to Microsoft's token endpoint. Entra ID validates the supplied username and password before rejecting the request because the application does not exist, so the returned error code reveals whether the credential and account are valid without ever producing a successful sign-in. A valid credential paired with a spoofed client ID returns `AADSTS700016` (application not found), an invalid password returns `AADSTS50126`, and a non-existent user returns `AADSTS50034`. Because the application never resolves, application-scoped Conditional Access is bypassed, and fragmenting requests across many random client IDs defeats per-application correlation and rate limiting. This behavior is used for stealthy user enumeration and password spraying (for example, the campaigns Proofpoint tracks as UNK_pyreq2323 and UNK_OutFlareAZ).
 38
 39This rule detects a ROPC authentication (`authentication_protocol: ropc`) that fails with `status.error_code: 700016` and carries no resolved `app_display_name`, the signature of a spoofed or non-existent client ID. This is a New Terms rule that triggers only when the application identifier (`app_id`) has not been observed in the tenant's sign-in logs in the previous 10 days, so each newly introduced spoofed client ID surfaces once rather than on every attempt.
 40
 41### Possible investigation steps
 42
 43- Review `azure.signinlogs.properties.app_id`: the value is a client ID that does not resolve to any registered application in the tenant. Determine whether the same principal or source is presenting many distinct or randomized client IDs (fragmentation) versus a single stable identifier (possible deleted app).
 44- Assess `azure.signinlogs.properties.user_principal_name`: a valid user account produces a sign-in log for this activity, so the targeted principal exists in the directory and its credentials are being probed. Prioritize privileged or high-value accounts.
 45- Correlate `azure.signinlogs.properties.status.error_code` for the same user and source over time. A shift from `50126` (invalid password) to `700016` (application not found) for the same account indicates the adversary has confirmed a valid credential, because the request advanced past credential validation.
 46- Review `source.ip`, `source.as.organization.name`, and `source.geo.country_name`: enumeration commonly originates from hosting providers, VPNs, or proxy infrastructure rather than corporate ranges.
 47- Inspect `user_agent.original` and `azure.signinlogs.properties.client_app_used`: scripted enumeration frequently uses generic HTTP libraries and logs `client_app_used` as `Unknown`.
 48- Pivot on the source IP or ASN to determine how many distinct user principals are being probed, which distinguishes targeted probing from broad spraying.
 49
 50### False positive analysis
 51
 52- A legitimate application deleted from the tenant while a client keeps authenticating against its former client ID via ROPC can produce `700016`. Such activity is typically a single, stable client ID at low volume, unlike the many distinct or randomized identifiers seen in spoofing.
 53- A misconfigured legacy client submitting an incorrect client ID may also trigger this rule. Confirm the client ID, the source, and whether the same principal is targeted by multiple unresolved client IDs before dismissing.
 54
 55### Response and remediation
 56
 57- If enumeration is confirmed, treat the targeted accounts as credential-probing targets: force password resets and revoke refresh tokens for any account where the error code progressed to `700016` (credential likely validated).
 58- Block the offending source IPs or ASNs at the firewall, proxy, or via Conditional Access named locations.
 59- Ensure MFA and Conditional Access are enforced for all user types, and disable legacy and ROPC authentication where not required, since ROPC cannot satisfy MFA.
 60- Audit targeted accounts for credential reuse across services and monitor for follow-on interactive or non-interactive sign-in success from the same source.
 61- Notify your identity security team and correlate with any concurrent brute-force or password-spray detections.
 62"""
 63references = [
 64    "https://www.proofpoint.com/us/blog/threat-insight/oauth-client-id-spoofing-why-fake-client-ids-are-gaining-traction-stealthy",
 65    "https://learn.microsoft.com/en-us/entra/identity-platform/reference-error-codes",
 66    "https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth-ropc",
 67]
 68risk_score = 47
 69rule_id = "a222b46e-eba8-492f-a376-b7f5f397a34f"
 70severity = "medium"
 71tags = [
 72    "Domain: Cloud",
 73    "Domain: Identity",
 74    "Data Source: Azure",
 75    "Data Source: Entra ID",
 76    "Data Source: Entra ID Sign-in Logs",
 77    "Use Case: Identity and Access Audit",
 78    "Use Case: Threat Detection",
 79    "Tactic: Credential Access",
 80    "Tactic: Discovery",
 81    "Resources: Investigation Guide",
 82]
 83timestamp_override = "event.ingested"
 84type = "new_terms"
 85
 86query = '''
 87data_stream.dataset: "azure.signinlogs"
 88    and event.category: "authentication"
 89    and azure.signinlogs.properties.authentication_protocol: "ropc"
 90    and azure.signinlogs.properties.status.error_code: 700016
 91    and not azure.signinlogs.properties.app_display_name: *
 92'''
 93
 94
 95[[rule.threat]]
 96framework = "MITRE ATT&CK"
 97[[rule.threat.technique]]
 98id = "T1110"
 99name = "Brute Force"
100reference = "https://attack.mitre.org/techniques/T1110/"
101[[rule.threat.technique.subtechnique]]
102id = "T1110.003"
103name = "Password Spraying"
104reference = "https://attack.mitre.org/techniques/T1110/003/"
105
106
107
108[rule.threat.tactic]
109id = "TA0006"
110name = "Credential Access"
111reference = "https://attack.mitre.org/tactics/TA0006/"
112[[rule.threat]]
113framework = "MITRE ATT&CK"
114[[rule.threat.technique]]
115id = "T1087"
116name = "Account Discovery"
117reference = "https://attack.mitre.org/techniques/T1087/"
118[[rule.threat.technique.subtechnique]]
119id = "T1087.004"
120name = "Cloud Account"
121reference = "https://attack.mitre.org/techniques/T1087/004/"
122
123
124
125[rule.threat.tactic]
126id = "TA0007"
127name = "Discovery"
128reference = "https://attack.mitre.org/tactics/TA0007/"
129
130[rule.investigation_fields]
131field_names = [
132    "@timestamp",
133    "azure.signinlogs.properties.user_principal_name",
134    "azure.signinlogs.properties.app_id",
135    "azure.signinlogs.properties.app_display_name",
136    "azure.signinlogs.properties.status.error_code",
137    "azure.signinlogs.properties.authentication_protocol",
138    "azure.signinlogs.properties.client_app_used",
139    "azure.signinlogs.category",
140    "source.ip",
141    "source.as.organization.name",
142    "source.geo.country_name",
143    "user_agent.original",
144    "event.outcome",
145]
146
147[rule.new_terms]
148field = "new_terms_fields"
149value = ["azure.signinlogs.properties.app_id"]
150[[rule.new_terms.history_window_start]]
151field = "history_window_start"
152value = "now-10d"

Triage and analysis

Investigating Entra ID ROPC Authentication with Unknown Client ID

Adversaries submit fabricated application identifiers (client IDs) in ROPC authentication requests to Microsoft's token endpoint. Entra ID validates the supplied username and password before rejecting the request because the application does not exist, so the returned error code reveals whether the credential and account are valid without ever producing a successful sign-in. A valid credential paired with a spoofed client ID returns AADSTS700016 (application not found), an invalid password returns AADSTS50126, and a non-existent user returns AADSTS50034. Because the application never resolves, application-scoped Conditional Access is bypassed, and fragmenting requests across many random client IDs defeats per-application correlation and rate limiting. This behavior is used for stealthy user enumeration and password spraying (for example, the campaigns Proofpoint tracks as UNK_pyreq2323 and UNK_OutFlareAZ).

This rule detects a ROPC authentication (authentication_protocol: ropc) that fails with status.error_code: 700016 and carries no resolved app_display_name, the signature of a spoofed or non-existent client ID. This is a New Terms rule that triggers only when the application identifier (app_id) has not been observed in the tenant's sign-in logs in the previous 10 days, so each newly introduced spoofed client ID surfaces once rather than on every attempt.

Possible investigation steps

  • Review azure.signinlogs.properties.app_id: the value is a client ID that does not resolve to any registered application in the tenant. Determine whether the same principal or source is presenting many distinct or randomized client IDs (fragmentation) versus a single stable identifier (possible deleted app).
  • Assess azure.signinlogs.properties.user_principal_name: a valid user account produces a sign-in log for this activity, so the targeted principal exists in the directory and its credentials are being probed. Prioritize privileged or high-value accounts.
  • Correlate azure.signinlogs.properties.status.error_code for the same user and source over time. A shift from 50126 (invalid password) to 700016 (application not found) for the same account indicates the adversary has confirmed a valid credential, because the request advanced past credential validation.
  • Review source.ip, source.as.organization.name, and source.geo.country_name: enumeration commonly originates from hosting providers, VPNs, or proxy infrastructure rather than corporate ranges.
  • Inspect user_agent.original and azure.signinlogs.properties.client_app_used: scripted enumeration frequently uses generic HTTP libraries and logs client_app_used as Unknown.
  • Pivot on the source IP or ASN to determine how many distinct user principals are being probed, which distinguishes targeted probing from broad spraying.

False positive analysis

  • A legitimate application deleted from the tenant while a client keeps authenticating against its former client ID via ROPC can produce 700016. Such activity is typically a single, stable client ID at low volume, unlike the many distinct or randomized identifiers seen in spoofing.
  • A misconfigured legacy client submitting an incorrect client ID may also trigger this rule. Confirm the client ID, the source, and whether the same principal is targeted by multiple unresolved client IDs before dismissing.

Response and remediation

  • If enumeration is confirmed, treat the targeted accounts as credential-probing targets: force password resets and revoke refresh tokens for any account where the error code progressed to 700016 (credential likely validated).
  • Block the offending source IPs or ASNs at the firewall, proxy, or via Conditional Access named locations.
  • Ensure MFA and Conditional Access are enforced for all user types, and disable legacy and ROPC authentication where not required, since ROPC cannot satisfy MFA.
  • Audit targeted accounts for credential reuse across services and monitor for follow-on interactive or non-interactive sign-in success from the same source.
  • Notify your identity security team and correlate with any concurrent brute-force or password-spray detections.

References

Related rules

to-top