↳ GitHub sourceAnalytics ruleHigh
Device Registration from Malicious IP
Description
This rule identifies successful Okta device registration events that originate from IP addresses also observed by Okta ThreatInsight as malicious or suspicious.
- Rule type
- Scheduled
- Version
- 1.1.2
- Declared status
- Available
- Query frequency
- 1h
- Query period
- 1h
- Trigger
- gt 0
Declared MITRE coverage
Declared sources
Metadata from the source file. No dependencies inferred from KQL.
Connectors
Data types
KQL query
Original query, unchanged.
let Events = dynamic(["device.enrollment.create"]);
let ThreatInsightOperations = dynamic(["security.threat.detected", "security.attack.start", "security.attack.end" ]);
// Adjust list of allowed IPs to reduce false positives
let AllowedIPs = dynamic([]);
let DeviceRegistrations = OktaSSO
| where eventType_s in (Events)
| where outcome_result_s == "SUCCESS"
| where isnotempty(client_ipAddress_s) and client_ipAddress_s !in (AllowedIPs)
| extend oktaDeviceId_ = tostring(parse_json(tostring(parse_json(target_s)[0].detailEntry)).oktaDeviceId), NewDevice_osPlatform = tostring(parse_json(tostring(parse_json(target_s)[0].detailEntry)).osPlatform), NewDevice_osVersion = tostring(parse_json(tostring(parse_json(target_s)[0].detailEntry)).osVersion), displayName_ = tostring(parse_json(target_s)[0].displayName)
| extend Location = strcat(client_geographicalContext_city_s, " | ", client_geographicalContext_state_s," | ", client_geographicalContext_country_s)
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_ipAddress_s, displayMessage_s, outcome_result_s,
outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s',""), client_userAgent_rawUserAgent_s,client_userAgent_browser_s, severity_s, NewDevice_osPlatform, NewDevice_osVersion, eventType_s, Location ;
let ThreatInsightEvents = OktaSSO
| where eventType_s in (ThreatInsightOperations)
| extend SuspiciousIP = actor_displayName_s
| project TimeGenerated, column_ifexists('debugContext_debugData_threatDetections_s', ""), client_userAgent_rawUserAgent_s, severity_s, outcome_result_s, eventType_s, displayMessage_s, SuspiciousIP, transaction_id_s;
DeviceRegistrations
| join kind=inner (ThreatInsightEvents) on $left.client_ipAddress_s == $right.SuspiciousIP
| project TimeGenerated, actor_alternateId_s, actor_displayName_s, client_ipAddress_s, client_userAgent_os_s, client_userAgent_rawUserAgent_s, client_userAgent_browser_s, displayMessage_s, outcome_result_s, outcome_reason_s, severity_s, NewDevice_osPlatform, NewDevice_osVersion, eventType_s, Location, SuspiciousIP, transaction_id_s
| extend AccountName = tostring(split(actor_alternateId_s, "@")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, "@")[1])
Declared entities
Related content
Links established from declared identifiers and solution manifests.
Source provenance
GitHubDisplayed values come from files in Azure/Azure-Sentinel. They describe the published template, not your workspace configuration.
- Commit
9800e51↗- Source identifier
e36c6bd6-f86a-4282-93a5-b4a1b48dd849
GSTEP / CATALOG TRACKING
Added to catalog : 16 Sept 2026 · 05:49 UTC
Last change observed : 16 Sept 2026 · 05:49 UTC