Problem
The rule Multiple Device Token Hashes for Single Okta Session (cc382a2e-7e52-11ee-9aac-f661ea17fbcd) is generating a high volume of alerts globally, with the vast majority left in open (untriaged) status — a strong signal that analysts are not finding value in the current alert volume.
Root Cause
The current threshold of count_distinct(dt_hash) >= 2 is too low. Okta's OAuth token grant flow naturally produces multiple device token hashes per session:
- A single authorization code -> access token + ID token exchange generates distinct dt_hash values for the request and response events
- This means a single legitimate OAuth flow already triggers the rule
Over half (~57%) of all alerts fire at exactly 2 unique device token hashes — the minimum threshold — and represent normal OAuth activity rather than session hijacking.
Additionally:
- The rule does not filter out
null or "-" values for dt_hash, which inflate the count_distinct calculation
- The alert document lacks contextual enrichment (no source IPs, ASN, geo, user agent, risk signals), forcing analysts to pivot into raw logs for every alert
Changes
Threshold Tuning
- Raise
count_distinct(dt_hash) threshold from >= 2 to >= 4
- Add
count_distinct(okta.client.ip) >= 2 as a secondary condition — session hijacking implies the adversary operates from a different source IP than the victim
Null/Dash Filtering
- Filter out
null and "-" values for okta.debug_context.debug_data.dt_hash, okta.authentication_context.external_session_id, and okta.client.user_agent.raw_user_agent before aggregation
- Filter out
null for okta.client.ip
Alert Enrichment via VALUES()
- Add
VALUES() aggregations for key triage fields so analysts have immediate context without pivoting to raw logs:
- Network:
okta.client.ip, client.geo.country_name, client.geo.city_name, source.as.number, source.as.organization.name
- Client:
okta.client.user_agent.raw_user_agent, okta.client.device, okta.security_context.is_proxy
- Session:
okta.debug_context.debug_data.dt_hash, event.action
- Risk:
okta.debug_context.debug_data.risk_level, okta.debug_context.debug_data.risk_reasons, okta.debug_context.debug_data.threat_suspected, okta.debug_context.debug_data.behaviors, okta.debug_context.debug_data.risk_behaviors
- Debug:
okta.debug_context.debug_data.device_fingerprint, okta.debug_context.debug_data.request_uri
- Add
min(@timestamp) / max(@timestamp) for event time window context
- Add
count(*) for total event count per session
Investigation Guide
- Updated investigation steps to reference stable Okta/ECS field names instead of dynamic
Esql.* fields
- Revised false positive analysis with realistic scenarios (OAuth integration flows, VPN/network transitions)
- Updated response and remediation with actionable steps tied to alert data
Index Pattern
- Narrowed from
logs-okta* to logs-okta.system-*
Other Changes
- Narrowed index pattern from
logs-okta* to logs-okta.system-* to match the data_stream.dataset filter
- Removed the
setup block (redundant with integration requirements)
- Updated tags: replaced
Use Case: Identity and Access Audit with Domain: Identity, added Data Source: Okta System Logs
- Added
interval = "8m" to align with the from = "now-9m" lookback
Expected Impact
- Eliminates the majority of alert noise by filtering out low-count dt_hash alerts caused by normal OAuth token flows
- Remaining alerts require both 4+ distinct device tokens and 2+ distinct source IPs — a high-confidence signal for session hijacking
- Enriched alert documents enable faster triage without raw log pivoting
Problem
The rule
Multiple Device Token Hashes for Single Okta Session(cc382a2e-7e52-11ee-9aac-f661ea17fbcd) is generating a high volume of alerts globally, with the vast majority left inopen(untriaged) status — a strong signal that analysts are not finding value in the current alert volume.Root Cause
The current threshold of
count_distinct(dt_hash) >= 2is too low. Okta's OAuth token grant flow naturally produces multiple device token hashes per session:Over half (~57%) of all alerts fire at exactly 2 unique device token hashes — the minimum threshold — and represent normal OAuth activity rather than session hijacking.
Additionally:
nullor"-"values fordt_hash, which inflate thecount_distinctcalculationChanges
Threshold Tuning
count_distinct(dt_hash)threshold from>= 2to>= 4count_distinct(okta.client.ip) >= 2as a secondary condition — session hijacking implies the adversary operates from a different source IP than the victimNull/Dash Filtering
nulland"-"values forokta.debug_context.debug_data.dt_hash,okta.authentication_context.external_session_id, andokta.client.user_agent.raw_user_agentbefore aggregationnullforokta.client.ipAlert Enrichment via VALUES()
VALUES()aggregations for key triage fields so analysts have immediate context without pivoting to raw logs:okta.client.ip,client.geo.country_name,client.geo.city_name,source.as.number,source.as.organization.nameokta.client.user_agent.raw_user_agent,okta.client.device,okta.security_context.is_proxyokta.debug_context.debug_data.dt_hash,event.actionokta.debug_context.debug_data.risk_level,okta.debug_context.debug_data.risk_reasons,okta.debug_context.debug_data.threat_suspected,okta.debug_context.debug_data.behaviors,okta.debug_context.debug_data.risk_behaviorsokta.debug_context.debug_data.device_fingerprint,okta.debug_context.debug_data.request_urimin(@timestamp)/max(@timestamp)for event time window contextcount(*)for total event count per sessionInvestigation Guide
Esql.*fieldsIndex Pattern
logs-okta*tologs-okta.system-*Other Changes
logs-okta*tologs-okta.system-*to match thedata_stream.datasetfiltersetupblock (redundant with integration requirements)Use Case: Identity and Access AuditwithDomain: Identity, addedData Source: Okta System Logsinterval = "8m"to align with thefrom = "now-9m"lookbackExpected Impact