Anthropic Session Reuse Impossible Travel

Last updated 5 days ago on 2026-09-21
Created 10 days ago on 2026-09-16

About

Detects successful Anthropic audit activity for the same user email from source IP addresses whose query-time geo-locations (via IP_LOCATION) span at least two countries, are separated by at least 500 km, and imply travel faster than 800 km/h within a short (~15-minute) lookback. Unlike login-only impossible travel, this rule covers any successful user-actor activity and can surface session cookie replay or concurrent session reuse when no new authentication events appear.
Tags
Domain: GenAIDomain: IdentityPlatform: AnthropicData Source: Anthropic Audit LogsUse Case: Identity and Access AuditUse Case: Threat DetectionRule Type: ES|QLTactic: Credential AccessTactic: Initial AccessLanguage: esql
Severity
high
Risk Score
73
MITRE ATT&CK™

Credential Access (TA0006)(external, opens in a new tab or window)

Initial Access (TA0001)(external, opens in a new tab or window)

False Positive Examples
Users on VPN or proxy egress that geo-resolves through a region distant from the user's physical location. Mobile clients on cellular networks that peer through regional hubs may geo-resolve differently than the user's location. Cloud egress, split-tunnel, or dual-homed clients that present different public IPs for concurrent Anthropic sessions (for example browser and API tooling) can look like impossible travel when both resolve far apart.
License
Elastic License v2(external, opens in a new tab or window)

Definition

Integration Pack
Prebuilt Security Detection Rules
Related Integrations

anthropic(external, opens in a new tab or window)

Query
text code block:
from logs-anthropic.audit-* | where data_stream.dataset == "anthropic.audit" and event.outcome == "success" and anthropic.audit.actor.type == "user_actor" and user.email is not null and source.ip is not null | IP_LOCATION geo = source.ip with { "properties": ["country_name", "city_name", "location"] } | eval Esql.source_geo_lat = st_y(geo.location), Esql.source_geo_lon = st_x(geo.location) | where Esql.source_geo_lat is not null and Esql.source_geo_lon is not null | stats Esql.first_lat = first(Esql.source_geo_lat, @timestamp), Esql.first_lon = first(Esql.source_geo_lon, @timestamp), Esql.last_lat = last(Esql.source_geo_lat, @timestamp), Esql.last_lon = last(Esql.source_geo_lon, @timestamp), Esql.event_count = count(*), Esql.country_count = count_distinct(geo.country_name), Esql.event_id_values = values(event.id), Esql.event_action_values = values(event.action), Esql.source_ip_values = values(source.ip), Esql.source_geo_country_name_values = values(geo.country_name), Esql.source_geo_city_name_values = values(geo.city_name), Esql.user_agent_original_values = values(user_agent.original), Esql.anthropic_audit_actor_type_values = values(anthropic.audit.actor.type), Esql.timestamp_first_seen = min(@timestamp), Esql.timestamp_last_seen = max(@timestamp) by user.email | where Esql.event_count >= 2 and Esql.country_count >= 2 | eval Esql.p1 = to_geopoint(concat("POINT(", to_string(Esql.first_lon), " ", to_string(Esql.first_lat), ")")), Esql.p2 = to_geopoint(concat("POINT(", to_string(Esql.last_lon), " ", to_string(Esql.last_lat), ")")) | eval Esql.distance_km = round(st_distance(Esql.p1, Esql.p2) / 1000.0, 0), Esql.window_minutes = date_diff("minute", Esql.timestamp_first_seen, Esql.timestamp_last_seen), Esql.travel_kmh = case(Esql.window_minutes > 0, round(Esql.distance_km * 60.0 / Esql.window_minutes, 0), null) | where Esql.distance_km >= 500 and Esql.travel_kmh >= 800 | keep user.email, Esql.*

Install detection rules in Elastic Security

Detect Anthropic Session Reuse Impossible Travel in the Elastic Security detection engine by installing this rule into your Elastic Stack.

To setup this rule, check out the installation guide for Prebuilt Security Detection Rules(external, opens in a new tab or window).