Multiple Device Token Hashes for Single Okta Session

edit
IMPORTANT: This documentation is no longer updated. Refer to Elastic's version policy and the latest documentation.

Multiple Device Token Hashes for Single Okta Session

edit

This rule detects when a specific Okta actor has multiple device token hashes and multiple source IPs for a single Okta session. This may indicate an authenticated session has been hijacked or replayed from a different device and network. Adversaries may steal session cookies or tokens to gain unauthorized access to Okta admin console, applications, tenants, or other resources.

Rule type: esql

Rule indices: None

Severity: medium

Risk score: 47

Runs every: 8m

Searches indices from: now-9m (Date Math format, see also Additional look-back time)

Maximum alerts per execution: 100

References:

Tags:

  • Domain: Identity
  • Domain: SaaS
  • Data Source: Okta
  • Data Source: Okta System Logs
  • Tactic: Credential Access
  • Resources: Investigation Guide

Version: 311

Rule authors:

  • Elastic

Rule license: Elastic License v2

Investigation guide

edit

Triage and analysis

Investigating Multiple Device Token Hashes for Single Okta Session

This rule detects when a specific Okta actor has multiple device token hashes and multiple source IPs for a single Okta session. This may indicate an authenticated session has been hijacked or replayed from a different device and network. Adversaries may steal session cookies or tokens to gain unauthorized access to Okta admin console, applications, tenants, or other resources.

Note: This is an ES|QL aggregation-based rule. Exceptions can be added on the original ECS or integration-related fields. We recommend using the indicators from the alert document to pivot into the raw events for analysis.

Possible investigation steps:

  • Use okta.actor.alternate_id and okta.authentication_context.external_session_id from the alert to pivot into the raw Okta system log events for the affected session.
  • Review the source IPs (okta.client.ip) and ASN information (source.as.organization.name) to determine if the session was used from multiple distinct networks.
  • Multiple ASNs or geolocations (client.geo.country_name, client.geo.city_name) within the same session strongly suggest session hijacking.
  • Compare the okta.debug_context.debug_data.dt_hash values to identify the device token hashes associated with the session.
  • A legitimate session should have a consistent device token hash. Multiple distinct hashes indicate the session cookie may have been replayed from a different device.
  • Examine okta.client.user_agent.raw_user_agent and okta.client.device for inconsistencies that suggest different devices or browsers using the same session.
  • Review event.action to understand what actions were performed during the session.
  • Look for suspicious post-authentication activity such as admin console access, policy changes, or application assignment modifications.
  • Check okta.debug_context.debug_data.risk_level, okta.debug_context.debug_data.risk_reasons, and okta.debug_context.debug_data.behaviors for Okta’s own risk assessment of the session activity.
  • Review the past activities of the actor(s) involved by checking their previous sessions and login patterns.

False positive analysis:

  • OAuth application integrations (e.g., backend services exchanging authorization codes for tokens) can generate multiple device token hashes per session due to the multi-step token grant flow. These typically involve Okta-Integrations user agents and known infrastructure IPs.
  • Users switching between networks (e.g., VPN reconnects, WiFi to cellular transitions) may produce multiple source IPs for the same session, though the device token hash should remain consistent.
  • Automated tools or scripts that interact with Okta APIs on behalf of a user may generate additional device token hashes.

Response and remediation:

  • If the alert shows multiple distinct ASNs or geolocations for the same session, immediately revoke all active sessions for the affected user via the Okta admin console.
  • Reset the user’s password and all active MFA factors.
  • If MFA is not enabled, enforce MFA enrollment before allowing re-authentication.
  • Review Okta system logs for any administrative or sensitive actions performed during the suspicious session window.
  • If the session was used to access downstream applications, review those application logs for unauthorized activity.
  • Check with the user to confirm whether they were actively using Okta during the alert time window.
  • For recurring false positives from known integrations, add exceptions on okta.actor.alternate_id for the specific service account or application client ID.

Rule query

edit
from logs-okta.system-*
| where
    data_stream.dataset == "okta.system" and
    not event.action in (
        "policy.evaluate_sign_on",
        "user.session.start",
        "user.authentication.sso"
    ) and
    okta.actor.alternate_id != "system@okta.com" and
    okta.actor.alternate_id rlike "[^@\\s]+\\@[^@\\s]+" and
    okta.authentication_context.external_session_id != "unknown" and
    (
        okta.authentication_context.external_session_id IS NOT NULL and
        okta.debug_context.debug_data.dt_hash IS NOT NULL and
        okta.client.ip IS NOT NULL and
        okta.client.user_agent.raw_user_agent IS NOT NULL
    ) and
    (
        okta.authentication_context.external_session_id != "-" and
        okta.debug_context.debug_data.dt_hash != "-" and
        okta.client.user_agent.raw_user_agent != "-"
    )
| stats
    Esql.dt_hash_count_distinct = count_distinct(okta.debug_context.debug_data.dt_hash),
    Esql.client_ip_count_distinct = count_distinct(okta.client.ip),
    Esql.event_count = count(*),
    Esql.first_event_time = min(@timestamp),
    Esql.last_event_time = max(@timestamp),
    Esql.dt_hash_values = values(okta.debug_context.debug_data.dt_hash),
    Esql.event_action_values = values(event.action),
    Esql.client_ip_values = values(okta.client.ip),
    Esql.user_agent_values = values(okta.client.user_agent.raw_user_agent),
    Esql.device_values = values(okta.client.device),
    Esql.is_proxy_values = values(okta.security_context.is_proxy),
    Esql.geo_country_name_values = values(client.geo.country_name),
    Esql.geo_city_name_values = values(client.geo.city_name),
    Esql.source_asn_number_values = values(source.`as`.number),
    Esql.source_asn_org_name_values = values(source.`as`.organization.name),
    Esql.threat_suspected_values = values(okta.debug_context.debug_data.threat_suspected),
    Esql.risk_level_values = values(okta.debug_context.debug_data.risk_level),
    Esql.risk_reasons_values = values(okta.debug_context.debug_data.risk_reasons),
    Esql.behaviors_values = values(okta.debug_context.debug_data.behaviors),
    Esql.device_fingerprint_values = values(okta.debug_context.debug_data.device_fingerprint),
    Esql.risk_behaviors_values = values(okta.debug_context.debug_data.risk_behaviors),
    Esql.request_uri_values = values(okta.debug_context.debug_data.request_uri)
  by
    okta.actor.alternate_id,
    okta.authentication_context.external_session_id
| where
    Esql.dt_hash_count_distinct >= 4 and
    Esql.client_ip_count_distinct >= 2
| keep Esql.*, okta.*

Framework: MITRE ATT&CKTM