Help us shape the future of Go! Take the 2026 Go Developer Survey

impossibletravel

package
v1.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 19 Imported by: 0

README

impossibletravel

Catches the case where the same account signs in from two places too far apart to have travelled between them.

The arithmetic is simple. Take the last login location, take this one, work out the distance and the elapsed time, and if the implied speed beats a passenger jet then something is wrong. Lagos at nine and Toronto at ten means one of those two sessions is not the account holder.

Use it when

  • Credential stuffing is a real problem for you and you want a signal that stolen passwords can't fake
  • You want a high-confidence account takeover alert. This check has very few false positives
  • You're feeding a SIEM and need events worth paging someone about

Skip it when

  • You are not running geoip, since there are no coordinates to measure without it
  • Your users sit behind a corporate proxy that egresses from a different continent to where they actually are
  • The account is brand new. The check needs a login history to compare against

Wiring

authsome.WithPlugin(geoip.New(geoip.Config{DatabasePath: "/var/lib/geoip/GeoLite2-City.mmdb"})),
authsome.WithPlugin(impossibletravel.New(impossibletravel.Config{
    MaxSpeedKmH: 900,
    Action:      "flag",
})),

Start on flag. Watch what it catches for a few weeks, then decide whether you're willing to move it to block.

Config

Field Type Default What it does
MaxSpeedKmH float64 900 Fastest speed treated as plausible. 900 km/h is roughly a commercial flight
MinDistanceKm float64 500 Distances under this are ignored, which keeps city-level GeoIP jitter out of the results
LookbackWindow time.Duration 24h How far back to search for the previous login
Action string flag flag records a security event. block refuses the sign-in

Settings

Key Default
impossibletravel.max_speed_kmh 900
impossibletravel.min_distance_km 500
impossibletravel.lookback_window_hours 24
impossibletravel.action flag

Lifecycle hooks

Hook What happens
AfterSignIn Compares this login against the previous one and flags or blocks
AfterPrincipalAuth Same check for non-user principals

Requires geoip. anomaly covers the softer patterns like odd hours and new devices, where this plugin only cares about physics.

Documentation

Overview

contract.go: Wires the impossibletravel plugin into the forge-dashboard contract surface via plugin.ContractContributor.

Package impossibletravel detects geographically impossible logins based on the time and distance between consecutive user logins.

Index

Constants

This section is empty.

Variables

View Source
var (
	// SettingMaxSpeedKmH is the maximum plausible travel speed in km/h.
	SettingMaxSpeedKmH = settings.Define("impossibletravel.max_speed_kmh", float64(900),
		settings.WithDisplayName("Max Speed (km/h)"),
		settings.WithDescription("Maximum plausible travel speed in km/h"),
		settings.WithCategory("Impossible Travel"),
		settings.WithScopes(settings.ScopeGlobal, settings.ScopeApp),
		settings.WithEnforceable(),
		settings.WithHelpText("Maximum plausible travel speed in km/h. Logins exceeding this are flagged."),
		settings.WithOrder(10),
	)

	// SettingMinDistanceKm is the minimum distance in km between logins to trigger a check.
	SettingMinDistanceKm = settings.Define("impossibletravel.min_distance_km", float64(500),
		settings.WithDisplayName("Min Distance (km)"),
		settings.WithDescription("Minimum distance in km between logins to trigger check"),
		settings.WithCategory("Impossible Travel"),
		settings.WithScopes(settings.ScopeGlobal, settings.ScopeApp),
		settings.WithHelpText("Minimum distance in km between logins to trigger check"),
		settings.WithOrder(20),
	)

	// SettingLookbackWindowHours is how far back to look for previous logins.
	SettingLookbackWindowHours = settings.Define("impossibletravel.lookback_window_hours", 24,
		settings.WithDisplayName("Lookback Window (hours)"),
		settings.WithDescription("How far back to look for previous logins, in hours"),
		settings.WithCategory("Impossible Travel"),
		settings.WithScopes(settings.ScopeGlobal, settings.ScopeApp),
		settings.WithHelpText("How far back to look for previous logins, in hours"),
		settings.WithOrder(30),
	)

	// SettingAction is the action to take when impossible travel is detected.
	SettingAction = settings.Define("impossibletravel.action", "flag",
		settings.WithDisplayName("Detection Action"),
		settings.WithDescription("Action to take when impossible travel is detected"),
		settings.WithCategory("Impossible Travel"),
		settings.WithScopes(settings.ScopeGlobal, settings.ScopeApp),
		settings.WithEnforceable(),
		settings.WithHelpText("Action to take when impossible travel is detected"),
		settings.WithOrder(40),
		settings.WithInputType(formconfig.FieldSelect),
		settings.WithOptions(
			formconfig.SelectOption{Label: "Flag Only", Value: "flag"},
			formconfig.SelectOption{Label: "Block", Value: "block"},
		),
	)
)

Functions

This section is empty.

Types

type Config

type Config struct {
	// MaxSpeedKmH is the maximum realistic travel speed (default: 900 km/h = airplane).
	MaxSpeedKmH float64

	// MinDistanceKm is the minimum distance to trigger a check (default: 500 km).
	MinDistanceKm float64

	// LookbackWindow is how far back to check login history (default: 24h).
	LookbackWindow time.Duration

	// Action is what to do on detection: "flag" (default), "block".
	Action string

	// MaxTrackedPrincipals bounds the in-memory last-login table; the
	// least recently seen principal is dropped when it is full (default:
	// 10000). A principal dropped from the table is checked afresh on its
	// next login, as if it had never logged in.
	MaxTrackedPrincipals int

	// MaxEvents bounds how many alerts are kept in memory for
	// RecordedEvents; older alerts are dropped (default: 1000). The audit
	// trail keeps every alert regardless.
	MaxEvents int
}

Config configures the impossible travel detection plugin.

type LoginLocation

type LoginLocation struct {
	// Principal is the caller this location belongs to: a user for sign-in,
	// an agent or workload for machine traffic.
	Principal principal.Ref
	IP        string
	Country   string
	City      string
	Latitude  float64
	Longitude float64
	LoginAt   time.Time
}

LoginLocation records a login position for travel calculation.

type Plugin

type Plugin struct {
	// contains filtered or unexported fields
}

Plugin detects impossible travel between consecutive logins.

func New

func New(cfg ...Config) *Plugin

New creates a new impossible travel detection plugin.

func (*Plugin) DeclareSettings

func (p *Plugin) DeclareSettings(m *settings.Manager) error

DeclareSettings implements plugin.SettingsProvider. It registers all impossible-travel-related configurable settings.

func (*Plugin) Name

func (p *Plugin) Name() string

Name returns the plugin name.

func (*Plugin) OnAfterPrincipalAuth

func (p *Plugin) OnAfterPrincipalAuth(ctx context.Context, a *principal.AuthAttempt, s *session.Session) error

OnAfterPrincipalAuth records a machine caller's login location and checks for impossible travel.

Keyed by principal rather than user. An agent has no user, and two agents sharing one travel history would score each other's movements as travel, which on a fleet spread across regions means a permanent false positive.

func (*Plugin) OnAfterSignIn

func (p *Plugin) OnAfterSignIn(ctx context.Context, u *user.User, s *session.Session) error

OnAfterSignIn records a person's login location and checks for impossible travel.

func (*Plugin) OnInit

func (p *Plugin) OnInit(_ context.Context, engine plugin.Engine) error

OnInit discovers engine dependencies.

func (*Plugin) RecordedEvents

func (p *Plugin) RecordedEvents() []TravelAlert

RecordedEvents returns the impossible-travel alerts raised so far, for tests to assert against.

func (*Plugin) RegisterContract

func (p *Plugin) RegisterContract(
	d *dispatcher.Dispatcher,
	reg contract.Registry,
	wreg contract.WardenRegistry,
	engine plugin.Engine,
) error

type TravelAlert

type TravelAlert struct {
	Principal       principal.Ref
	SessionID       id.SessionID
	FromLocation    LoginLocation
	ToLocation      LoginLocation
	DistanceKm      float64
	TimeDeltaMin    float64
	RequiredSpeedKm float64
	RiskLevel       string
}

TravelAlert is emitted when impossible travel is detected.

Directories

Path Synopsis
Package contract wires the impossibletravel plugin's deep-link settings page into the forge-dashboard contract registry.
Package contract wires the impossibletravel plugin's deep-link settings page into the forge-dashboard contract registry.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL