↳ 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

AccountIP

Related content

Links established from declared identifiers and solution manifests.

Source provenance

GitHub

Displayed values come from files in Azure/Azure-Sentinel. They describe the published template, not your workspace configuration.

Source identifier
e36c6bd6-f86a-4282-93a5-b4a1b48dd849
Additional source files 2Solutions/Okta Single Sign-On/Analytic Rules/DeviceRegistrationMaliciousIP.yamlsource ↗Solutions/Okta Single Sign-On/data/Solution_Okta.jsonsolution-membership ↗
GSTEP / CATALOG TRACKING

Added to catalog : 16 Sept 2026 · 05:49 UTC
Last change observed : 16 Sept 2026 · 05:49 UTC

GSTEP sync dates, separate from the source content’s publication dates.