Login location tracking (country/city/IP)
Why it matters
Login location tracking is the baseline dataset for detecting impossible travel, account sharing, and unauthorized access patterns. Without it, there is no ground truth for anomaly detection — you cannot identify a login from Russia 10 minutes after a login from New York if no location is recorded. PCI-DSS Req 10.2.1 requires that access attempts include origin context. NIST AU-3 mandates that audit records capture location where applicable. ISO 27001:2022 A.8.15 requires traceability of access events. In financial fraud investigations, login location records are often the primary evidence used to distinguish legitimate from unauthorized transactions.
Severity rationale
Low because location tracking does not prevent unauthorized access on its own, but without it, anomaly detection, fraud investigation, and incident response lose the geographic context needed to identify suspicious login patterns.
Remediation
Add geolocation capture to the login handler in src/lib/geoLocation.ts using a local lookup library to avoid external API dependency:
import geoip from 'geoip-lite'; // local MaxMind DB — no external calls
export function trackLoginLocation(req: Request) {
const ip = getClientIP(req);
const geo = geoip.lookup(ip);
return {
ip,
country: geo?.country ?? null,
city: geo?.city ?? null,
timestamp: new Date()
};
}
Store the result on the session record at creation time:
const location = trackLoginLocation(req);
await db.sessions.create({
data: { userId, location, device: parseUserAgent(req), expiresAt }
});
Capture at minimum: IP, country, and city — that is the three-field minimum. Keep geoip-lite's MaxMind database updated monthly to maintain lookup accuracy.
Detection
- ID:
login-location-tracking - Severity:
low - What to look for: Count all location tracking data fields in session records (IP, country, city, region). Quote the actual geolocation library found (geoip-lite, maxmind, ip2location). Enumerate the session columns that store location data. Verify at least 3 location fields are recorded per login.
- Pass criteria: Login attempts record at least 3 location fields: IP address, country, and city. Data is stored with the session record. Report the count even on pass (e.g., "3 location fields: ip, country, city — via geoip-lite, stored in sessions table").
- Fail criteria: Login location not tracked (0 location fields), or only IP recorded without geolocation (fewer than 3 fields).
- Skip (N/A) when: The application does not require location tracking — cite the actual compliance requirements found.
- Detail on fail:
"0 location fields recorded on login — no IP, no geolocation"or"IP recorded but 0 geolocation fields (no country or city) — 1 of 3 required fields" - Remediation: Add IP geolocation to login (in
src/lib/geoLocation.ts):// lib/geoLocation.ts import geoip from 'geoip-lite'; export async function trackLoginLocation(req: Request) { const ip = getClientIP(req); const geo = geoip.lookup(ip); return { ip, country: geo?.country, city: geo?.city, timestamp: new Date() }; } // In login endpoint const location = await trackLoginLocation(req); await db.sessions.create({ userId, location, device: parseUserAgent(req), expiresAt: sessionExpiry });
External references
- nist:rev5 · AU-3 — Content of Audit Records
- pci-dss:4.0 · Req 10.2.1 — Audit log captures origination of action including IP
- iso-27001:2022 · A.8.15 — Logging
Taxons
History
- 2026-04-18·v1.0.0·Initial import from finserv-session-security·automated