Okta Successful Login After Credential Attack

Correlates Okta credential attack alerts with subsequent successful authentication for the same user account, identifying potential compromise following brute force, password spray, or credential stuffing attempts.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/02/12"
  3integration = ["okta"]
  4maturity = "production"
  5updated_date = "2026/09/18"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Correlates Okta credential attack alerts with subsequent successful authentication for the same user account,
 11identifying potential compromise following brute force, password spray, or credential stuffing attempts.
 12"""
 13false_positives = [
 14    "A user experiencing legitimate login issues (forgotten password, typos) may trigger credential attack alerts before successfully authenticating.",
 15    "Automated password reset flows where a user fails multiple times then succeeds after resetting their password.",
 16]
 17from = "now-6h"
 18interval = "30m"
 19language = "esql"
 20license = "Elastic License v2"
 21name = "Okta Successful Login After Credential Attack"
 22note = """## Triage and analysis
 23
 24### Investigating Okta Successful Login After Credential Attack
 25
 26This rule correlates credential attack alerts with subsequent successful authentication for the same user account. The correlation is user-centric, capturing IP rotation scenarios where attackers may login from a different IP after obtaining credentials.
 27
 28#### Possible investigation steps
 29- Identify the user account and review the timeline between the attack and successful login.
 30- Compare the attack source IPs versus the login source IP to identify potential IP rotation.
 31- Review the original credential attack alert to understand the scope and nature of the attack.
 32- Check the authentication method used and whether MFA was required and satisfied.
 33- Review the session activity following the successful login for signs of account takeover.
 34- Verify with the user if the login was legitimate.
 35
 36### False positive analysis
 37- Users experiencing legitimate login issues may trigger attack alerts before successfully authenticating.
 38- Automated password reset flows where a user fails multiple times then succeeds after resetting may trigger this rule.
 39- The rule correlates on user identity only, so it fires when a user is targeted and later logs in, even if from different IPs.
 40
 41### Response and remediation
 42- If compromise is suspected, reset the user's password and revoke all active sessions.
 43- Reset MFA if the attacker may have enrolled their own device.
 44- Block the source IP at the network perimeter.
 45- Review the user's recent activity for signs of lateral movement or data access.
 46- Check for persistence mechanisms such as new OAuth apps, API tokens, or enrolled devices.
 47"""
 48references = [
 49    "https://support.okta.com/help/s/article/Troubleshooting-Distributed-Brute-Force-andor-Password-Spray-attacks-in-Okta",
 50    "https://www.okta.com/identity-101/brute-force/",
 51    "https://developer.okta.com/docs/reference/api/system-log/",
 52    "https://developer.okta.com/docs/reference/api/event-types/",
 53    "https://www.elastic.co/security-labs/testing-okta-visibility-and-detection-dorothy",
 54    "https://www.elastic.co/security-labs/monitoring-okta-threats-with-elastic-security",
 55    "https://www.elastic.co/security-labs/starter-guide-to-understanding-okta",
 56]
 57risk_score = 73
 58rule_id = "50742e15-c5ef-49c8-9a2d-31221d45af58"
 59setup = """## Setup
 60
 61This rule requires the following:
 621. The Okta Fleet integration, Filebeat module, or similarly structured data for Okta System Logs.
 632. The correlated credential attack detection rules must be enabled (at least one):
 64   - Potential Okta Credential Stuffing (Single Source) (94e734c0-2cda-11ef-84e1-f661ea17fbce)
 65   - Potential Okta Password Spray (Single Source) (42bf698b-4738-445b-8231-c834ddefd8a0)
 66   - Potential Okta Brute Force (Device Token Rotation) (23f18264-2d6d-11ef-9413-f661ea17fbce)
 67   - Potential Okta Brute Force (Multi-Source) (5889760c-9858-4b4b-879c-e299df493295)
 68   - Potential Okta Password Spray (Multi-Source) (2d3c27d5-d133-4152-8102-8d051619ec4a)
 693. Alerts from these rules must be written to the `.alerts-security.*` indices.
 70
 71The rule queries both alert indices and Okta log indices to correlate attack alerts with successful logins."""
 72severity = "high"
 73tags = [
 74    "Domain: Identity",
 75    "Use Case: Identity and Access Audit",
 76    "Use Case: Threat Detection",
 77    "Data Source: Okta",
 78    "Data Source: Okta System Logs",
 79    "Tactic: Credential Access",
 80    "Tactic: Initial Access",
 81    "Resources: Investigation Guide",
 82    "Rule Type: Higher-Order Rule",
 83    "Noise: Low",
 84    "Performance: Fast",
 85    "Profile: Recommended",
 86    "Rule Type: ES|QL",
 87    "Platform: Okta",
 88]
 89timestamp_override = "event.ingested"
 90type = "esql"
 91
 92query = '''
 93FROM .alerts-security.*, logs-okta.system-* METADATA _id, _version, _index
 94// Filter for credential attack alerts OR successful Okta authentications
 95| WHERE
 96    (
 97        // Credential attack alerts from the five correlated rules
 98        kibana.alert.rule.rule_id IN (
 99            "94e734c0-2cda-11ef-84e1-f661ea17fbce",  // Credential Stuffing
100            "42bf698b-4738-445b-8231-c834ddefd8a0",  // Password Spraying
101            "23f18264-2d6d-11ef-9413-f661ea17fbce",  // DT Brute Force
102            "5889760c-9858-4b4b-879c-e299df493295",  // Distributed Brute Force
103            "2d3c27d5-d133-4152-8102-8d051619ec4a"   // Distributed Spray
104        )
105    )
106    OR (
107        // Successful Okta authentication events
108        data_stream.dataset == "okta.system"
109        AND (event.action LIKE "user.authentication.*" OR event.action == "user.session.start")
110        AND okta.outcome.result == "SUCCESS"
111        AND okta.actor.alternate_id IS NOT NULL
112    )
113// correlation - alerts may store user/IP in different fields than raw logs
114| EVAL
115    Esql.user = COALESCE(okta.actor.alternate_id, user.name, user.email),
116    Esql.source_ip = COALESCE(okta.client.ip, client.ip, source.ip)
117// Must have user identity to correlate
118| WHERE Esql.user IS NOT NULL
119// Classify events and capture timestamps/IPs by event type
120| EVAL
121    Esql.is_attack_alert = CASE(
122        kibana.alert.rule.rule_id IN (
123            "94e734c0-2cda-11ef-84e1-f661ea17fbce",
124            "42bf698b-4738-445b-8231-c834ddefd8a0",
125            "23f18264-2d6d-11ef-9413-f661ea17fbce",
126            "5889760c-9858-4b4b-879c-e299df493295",
127            "2d3c27d5-d133-4152-8102-8d051619ec4a"
128        ), 1, 0
129    ),
130    Esql.is_success_login = CASE(
131        data_stream.dataset == "okta.system"
132        AND okta.outcome.result == "SUCCESS", 1, 0
133    ),
134    Esql.attack_ip = CASE(
135        kibana.alert.rule.rule_id IN (
136            "94e734c0-2cda-11ef-84e1-f661ea17fbce",
137            "42bf698b-4738-445b-8231-c834ddefd8a0",
138            "23f18264-2d6d-11ef-9413-f661ea17fbce",
139            "5889760c-9858-4b4b-879c-e299df493295",
140            "2d3c27d5-d133-4152-8102-8d051619ec4a"
141        ), Esql.source_ip, null
142    ),
143    Esql.login_ip = CASE(
144        data_stream.dataset == "okta.system"
145        AND okta.outcome.result == "SUCCESS", Esql.source_ip, null
146    ),
147    Esql.attack_ts = CASE(
148        kibana.alert.rule.rule_id IN (
149            "94e734c0-2cda-11ef-84e1-f661ea17fbce",
150            "42bf698b-4738-445b-8231-c834ddefd8a0",
151            "23f18264-2d6d-11ef-9413-f661ea17fbce",
152            "5889760c-9858-4b4b-879c-e299df493295",
153            "2d3c27d5-d133-4152-8102-8d051619ec4a"
154        ), @timestamp, null
155    ),
156    Esql.login_ts = CASE(
157        data_stream.dataset == "okta.system"
158        AND okta.outcome.result == "SUCCESS", @timestamp, null
159    )
160// Aggregate by user (catches IP rotation: spray from IP A, login from IP B)
161| STATS
162    Esql.attack_count = SUM(Esql.is_attack_alert),
163    Esql.login_count = SUM(Esql.is_success_login),
164    Esql.earliest_attack = MIN(Esql.attack_ts),
165    Esql.latest_attack = MAX(Esql.attack_ts),
166    Esql.earliest_login = MIN(Esql.login_ts),
167    Esql.latest_login = MAX(Esql.login_ts),
168    Esql.attack_source_ips = VALUES(Esql.attack_ip),
169    Esql.login_source_ips = VALUES(Esql.login_ip),
170    Esql.all_source_ips = VALUES(Esql.source_ip),
171    Esql.alert_rule_ids = VALUES(kibana.alert.rule.rule_id),
172    Esql.alert_rule_names = VALUES(kibana.alert.rule.name),
173    Esql.event_action_values = VALUES(event.action),
174    Esql.geo_country_values = VALUES(client.geo.country_name),
175    Esql.geo_city_values = VALUES(client.geo.city_name),
176    Esql.source_asn_values = VALUES(source.as.number),
177    Esql.source_asn_org_values = VALUES(source.as.organization.name),
178    Esql.user_agent_values = VALUES(okta.client.user_agent.raw_user_agent),
179    Esql.device_values = VALUES(okta.client.device),
180    Esql.is_proxy_values = VALUES(okta.security_context.is_proxy)
181  BY Esql.user
182// Calculate time gap between latest attack and earliest subsequent login
183| EVAL Esql.attack_to_login_minutes = DATE_DIFF("minute", Esql.latest_attack, Esql.earliest_login)
184// Correlation: attack BEFORE login + success within reasonable window (3 hours)
185| WHERE
186    Esql.attack_count > 0
187    AND Esql.login_count > 0
188    AND Esql.latest_attack < Esql.earliest_login
189    AND Esql.attack_to_login_minutes <= 180
190| SORT Esql.login_count DESC
191| KEEP Esql.*
192'''
193
194
195[[rule.threat]]
196framework = "MITRE ATT&CK"
197[[rule.threat.technique]]
198id = "T1110"
199name = "Brute Force"
200reference = "https://attack.mitre.org/techniques/T1110/"
201[[rule.threat.technique.subtechnique]]
202id = "T1110.001"
203name = "Password Guessing"
204reference = "https://attack.mitre.org/techniques/T1110/001/"
205
206[[rule.threat.technique.subtechnique]]
207id = "T1110.003"
208name = "Password Spraying"
209reference = "https://attack.mitre.org/techniques/T1110/003/"
210
211[[rule.threat.technique.subtechnique]]
212id = "T1110.004"
213name = "Credential Stuffing"
214reference = "https://attack.mitre.org/techniques/T1110/004/"
215
216
217
218[rule.threat.tactic]
219id = "TA0006"
220name = "Credential Access"
221reference = "https://attack.mitre.org/tactics/TA0006/"
222[[rule.threat]]
223framework = "MITRE ATT&CK"
224[[rule.threat.technique]]
225id = "T1078"
226name = "Valid Accounts"
227reference = "https://attack.mitre.org/techniques/T1078/"
228[[rule.threat.technique.subtechnique]]
229id = "T1078.004"
230name = "Cloud Accounts"
231reference = "https://attack.mitre.org/techniques/T1078/004/"
232
233
234
235[rule.threat.tactic]
236id = "TA0001"
237name = "Initial Access"
238reference = "https://attack.mitre.org/tactics/TA0001/"

Triage and analysis

Investigating Okta Successful Login After Credential Attack

This rule correlates credential attack alerts with subsequent successful authentication for the same user account. The correlation is user-centric, capturing IP rotation scenarios where attackers may login from a different IP after obtaining credentials.

Possible investigation steps

  • Identify the user account and review the timeline between the attack and successful login.
  • Compare the attack source IPs versus the login source IP to identify potential IP rotation.
  • Review the original credential attack alert to understand the scope and nature of the attack.
  • Check the authentication method used and whether MFA was required and satisfied.
  • Review the session activity following the successful login for signs of account takeover.
  • Verify with the user if the login was legitimate.

False positive analysis

  • Users experiencing legitimate login issues may trigger attack alerts before successfully authenticating.
  • Automated password reset flows where a user fails multiple times then succeeds after resetting may trigger this rule.
  • The rule correlates on user identity only, so it fires when a user is targeted and later logs in, even if from different IPs.

Response and remediation

  • If compromise is suspected, reset the user's password and revoke all active sessions.
  • Reset MFA if the attacker may have enrolled their own device.
  • Block the source IP at the network perimeter.
  • Review the user's recent activity for signs of lateral movement or data access.
  • Check for persistence mechanisms such as new OAuth apps, API tokens, or enrolled devices.

References

Related rules

to-top