UEBADecember 20259 min read

Impossible Travel Detection: Building a Geospatial UEBA Model

How DKTrace's ml-engine calculates whether a login sequence is physically possible using Haversine distance, timestamps, and realistic travel speeds — including VPN, CDN, and NAT gateway edge cases.

DK

DKTrace Research Team

Security Engineering · Threat Research

The Problem

Impossible Travel is simple in principle: if User A logs in from London at 09:00 and from Lagos at 09:47, they cannot have physically travelled there.

In production SOC environments, naive implementations generate enormous false-positive volumes from:

Corporate VPN exit nodes (a London user appears as New York)
Cloud NAT gateways (AWS us-east-1 exits via Virginia)
CDN edge nodes (Cloudflare proxies authentication requests)
IPv6 geolocation inaccuracy (up to 500km off for mobile IPs)

DKTrace's Approach

The ml-engine maintains a geo-velocity profile for every entity:

Per-user historical login locations (90-day rolling window)
Known corporate VPN exit nodes (synced hourly from asset-manager)
Known cloud NAT CIDR ranges (AWS, Azure, GCP — updated daily from cspm)
CDN edge node ranges (Cloudflare, Akamai, Fastly)

The Algorithm

python
def check_impossible_travel(login_event):
    prev = get_last_login(login_event.user_id)
    if not prev:
        return  # No baseline yet

    distance_km = haversine(
        prev.latitude, prev.longitude,
        login_event.latitude, login_event.longitude
    )
    time_hours = (login_event.timestamp - prev.timestamp).total_seconds() / 3600
    
    if time_hours < 0.01:  # same-second logins = shared session token
        return
    
    speed_kmh = distance_km / time_hours

    if speed_kmh > 900:  # commercial aircraft max
        if (login_event.src_ip not in vpn_ranges and
            login_event.src_ip not in cdn_ranges and
            login_event.src_ip not in cloud_nat_ranges):
            
            risk_delta = min(40, speed_kmh / 25)
            ueba_score_update(login_event.user_id, risk_delta)
            fire_alert("T1078", confidence="HIGH", speed_kmh=speed_kmh)

False Positive Suppression Rules

DKTrace suppresses the alert when any of these apply:

1Both IPs belong to the same /16 subnet (same ISP NAT pool)
2Source IP changed but User-Agent, TLS fingerprint, and device ID are identical
3User has authenticated from both locations within the past 30 days with no anomaly
4The "distant" IP is in the user's registered travel schedule (if calendar integration enabled)
5Speed is under 1,100 km/h (allows for supersonic travel — rare but possible for government customers)

Production Results (Banking Deployment)

Over 90 days:

847 impossible travel events detected
23 confirmed account compromise via credential stuffing
False positive rate: 2.1% (18 events from misconfigured VPN exit nodes, resolved by adding to VPN CIDR list)

See It Live

Watch DKTrace detect this threat in your environment

Our engineers will run a live detection simulation against a sample of your log telemetry — no agents, no commitment.

Request a Live Demo