IP Geolocation for Cybersecurity Ops — SOC/SIEM Enrichment, Zero-Trust Step-Up, EDR/XDR C2 Detection, NIS2 + DORA + SOC2 + CMMC Audit Routing

Why cybersecurity ops is its own axis: every SIEM event ingested by Splunk / Elastic / Sentinel / Chronicle / Sumo Logic, every IAM authentication evaluated by Okta / Entra ID / Auth0 / Ping / ForgeRock, every EDR/XDR alert raised by CrowdStrike / SentinelOne / Microsoft Defender / Palo Alto Cortex / Trend Vision One, and every compliance attestation rendered for NIS2 / DORA / SOC 2 / ISO 27001 / CMMC 2.0 / EU CRA is a four-jurisdiction decision in <40 ms — SOC/SIEM event-enrichment + threat-intel-feed correlation at log-ingest (Tor / VPN / residential-proxy / hosting-ASN classification on every source IP), zero-trust IAM step-up + impossible-travel + ASN-flip detection at authentication, EDR/XDR alert triage + command-and-control (C2) egress detection via ASN-classification, and NIS2 Art. 21 + DORA Art. 10-14 + SOC 2 CC6 + ISO 27001 A.5/A.8 + CMMC 2.0 Level 2 audit-trail routing per jurisdiction. IP-layer signals are upstream of the SIEM correlation rule, the IAM risk engine, the EDR detection content, the SOAR playbook, and the post-incident regulator + auditor + cyber-insurance evidence bundle. A wrong-country resolve at log-ingest either burns alert-budget on false-positive ASN flips (Pareto: top-10 hosting/VPN ASNs generate ~60% of false-positive C2 alerts per MITRE ATT&CK 2024 telemetry) or breaches NIS2 Art. 23 + DORA Art. 19 + GDPR Art. 33 incident-notification windows (24h / 72h / 4h respectively).

The country an IP resolves to, the ASN-as-hosting vs ASN-as-residential vs ASN-as-VPN-relay vs ASN-as-Tor-exit it sits on, and whether it sits in a known datacenter, VPN provider, residential-proxy network, anonymising relay, or Tor exit are inputs to four separate cybersecurity-ops control surfaces:

  1. SOC/SIEM event-enrichment + threat-intel-feed correlation at log-ingest — every SIEM correlation rule consuming firewall logs, WAF logs, VPC flow logs, Cloudtrail / Azure Activity Log / Google Audit Log, AD/Entra sign-in logs, Okta system log, Slack/Teams/Zoom audit-log, M365 Unified Audit Log, GitHub audit-log, GitLab audit-events, AWS GuardDuty findings, Azure Defender alerts, GCP SCC findings, and EDR telemetry needs IP-geo enrichment at ingest-time (Splunk iplocation command, Elastic geoip processor, Sentinel iplocation KQL, Chronicle ipgeolocation UDM enrichment, Sumo lookup table). Hard-fail-closed thresholds: source IP in Tor-exit list (TorProject check.torproject.org + dan.me.uk feed) + sensitive-resource access → high-severity alert + auto-block in WAF; residential-proxy ASN (Bright Data AS207990 + Oxylabs AS44946 + Smartproxy AS133752 + IPRoyal AS208045 + NetNut AS61317 + SOAX AS398465 + Geosurf AS199524) + admin-credential use → impossible-topology alert (admin should never authenticate via residential-proxy); hosting ASN (AWS AS16509 + GCP AS396982 + Azure AS8075 + DigitalOcean AS14061 + Hetzner AS24940 + OVH AS16276 + Linode AS63949 + Vultr AS20473) on consumer-app endpoint that should only see residential ISP traffic → flag as bot / scanner (Pareto: ~40% of credential-stuffing originates from datacenter ASN per Cloudflare Radar 2024); known-state-actor ASN egress (per CISA AA24-XXX advisories + UK NCSC + ANSSI + BSI joint advisories) → P1 incident + 24h NIS2 notification countdown. Threat-feed correlation: IP in Mandiant + Recorded Future + Anomali + EclecticIQ + Group-IB + AlienVault OTX + abuse.ch + AbuseIPDB + Spamhaus DROP/EDROP + FireHOL feeds → severity boost in the SIEM correlation rule.
  2. Zero-trust IAM step-up + impossible-travel + ASN-flip detection at authentication — every IAM authentication evaluated by Okta / Entra ID Conditional Access / Auth0 / Ping / ForgeRock / Duo / Cisco DUO / JumpCloud / OneLogin / Centrify consumes IP-country + ASN + threat-fields as zero-trust signals. Hard-fail-closed: prior-session IP-country ≠ current-session IP-country AND time-delta < session-half-life → impossible-travel-flag + step-up to phishing-resistant MFA (FIDO2/WebAuthn per CISA Zero Trust Maturity Model v2 + NIST SP 800-207). ASN-flip detection: prior-session ASN ≠ current-session ASN AND classified-as-VPN/proxy/Tor → step-up + risk-score boost (Okta ThreatInsight + Entra ID Identity Protection + Auth0 Adaptive MFA all consume this signal). Hosting ASN on user-credential authentication → reject + force password reset (user credentials should never authenticate from AWS/GCP — indicates credential leak + scripted attack). Sanctioned country origin (US OFAC SDN + EU CONSILIUM + UK OFSI + UN 1267 sanctions list) → hard-stop + escalate to OFAC/Treasury compliance team (per OFAC 2024 enforcement: ~$1.5B in fines for US sanctions-screening failures including hosting-ASN-cloaked origin). Privileged-access management (PAM) integration: CyberArk / Delinea / BeyondTrust / HashiCorp Boundary admin-session origin IP must be on corporate-allowlist + non-anonymising → otherwise block-then-page-on-call SOC analyst (CrowdStrike OverWatch 2024 IR Report: 71% of hands-on-keyboard intrusions used compromised admin accounts; ~38% originated from VPN/Tor ASN).
  3. EDR/XDR alert triage + command-and-control (C2) egress detection via ASN-classification — every EDR/XDR alert raised by CrowdStrike Falcon / SentinelOne Singularity / Microsoft Defender for Endpoint / Palo Alto Cortex XDR / Trend Vision One / Sophos XDR / SentinelOne Vigilance / Carbon Black needs IP-geo + ASN-classification on the suspect destination IP to discriminate legitimate cloud-service traffic (is_hosting=true + ASN-org “AWS/GCP/Azure” + destination port 443) from C2 egress (is_hosting=true + ASN-org bulletproof-hosting “Hosting Yandex.Cloud / NiceVPS / FlokiNET / DDoS-Guard AS262254 / 1337team AS210848 / King Servers AS44724 / FBW Networks SAS AS197695”) via the same IP class. Hard-fail-closed: outbound TLS to known C2-infrastructure ASN (per Mandiant + Recorded Future + Microsoft Defender Threat Intelligence ATP feeds) → auto-isolate endpoint via EDR Network Containment + ticket SOC. JA3/JA4 TLS fingerprint + IP-geo correlation: JA3 hash matches Cobalt Strike + IP geo not in expected business-region → P1 alert (MITRE ATT&CK T1071.001 Application Layer Protocol: Web Protocols). Beacon-interval + jitter analysis cross-referenced with IP-geo: same-host outbound to single foreign-ASN destination at regular intervals (300s ± jitter) → flag as C2 beacon (MITRE T1029 Scheduled Transfer). Living-off-the-land + LOLBin egress: powershell.exe / certutil.exe / bitsadmin.exe / msbuild.exe initiating outbound TLS to hosting-ASN with no prior business-need → block-on-detection (Microsoft 2024 SOPHOS X-Ops: ~52% of ransomware deployments use LOLBin + cloud-hosting C2). VPN/residential-proxy in outbound endpoint telemetry: workstation initiating outbound to Bright Data / Oxylabs / Smartproxy → DLP/exfil-suspect (data egress through residential-proxy is anti-detection technique per MITRE T1090.002 External Proxy).
  4. NIS2 + DORA + SOC 2 + ISO 27001 + CMMC + EU CRA jurisdiction routing at audit-trail termination — every cybersecurity-ops session is subject to layered compliance obligations: EU NIS2 Directive 2022/2555 (transposed 2024-10-17, OES + DSP + new “essential” + “important” entity classes, Art. 21 risk-management + Art. 23 24h-early-warning / 72h-incident-notification / 1-month-final-report), EU DORA Regulation 2022/2554 (applicable 2025-01-17, ICT-risk Art. 5-14 + ICT-incident Art. 17-23 + threat-led-pen-test Art. 24-27 + third-party-ICT-risk Art. 28-44 + 4h-major-incident notification), SOC 2 Type II Trust Services Criteria CC6 (Logical Access) + CC7 (System Operations) + CC8 (Change Management), ISO/IEC 27001:2022 Annex A.5 (Organizational) + A.6 (People) + A.7 (Physical) + A.8 (Technological), CMMC 2.0 Level 2 (NIST SP 800-171 + DFARS 252.204-7012, US-DoD-contractor + CUI-handling), EU CRA (Cyber Resilience Act 2024/2847, applicable 2027-12, security-by-default + 24h-vulnerability-notification + 24h-active-exploitation-notification to ENISA), US Executive Order 14028 + OMB M-22-09 zero-trust, NIST SP 800-207 ZTA + 800-53 Rev. 5 SC + AC families, UK NCSC Cyber Assessment Framework (CAF), AU ACSC Essential Eight + ISM, IN CERT-In Cyber Security Directions (April 2022, 6h incident reporting), JP NISC Cybersecurity Strategy. IP-resolve at log-ingest routes the alert evidence + audit-trail + regulator-notification artifact to the correct national CSIRT + competent-authority gateway: EU-entity incident → ENISA + national CSIRT (DE BSI Meldepflicht, FR ANSSI signalement, NL NCSC-NL meldplicht, IT ACN segnalazione, IE NCSC notification, AT GovCERT.gv.at, ES CCN-CERT, PL CERT.PL, BE CCB notify); US-entity → CISA + sector-ISAC (FS-ISAC, H-ISAC, E-ISAC, A-ISAC); UK-entity → NCSC + ICO 72h breach-notification + regulator-specific (PRA SS1/21, FCA SYSC 13); CN-entity → MIIT + CAC + sector-CERT; IN-entity → CERT-In 6h-window. VPN/proxy/Tor origin on incident-pivot-IP → fall back to highest-protection EU-FRA shard + flag for manual attribution-eval. Wrong notification = €10M-2%-global-turnover NIS2 fine + €10M-2%-global-turnover DORA fine + SOC 2 qualified-opinion + ISO 27001 nonconformity + CMMC Level 2 fail (BSI 2024: €2.3M fine on DE energy operator for missed 24h NIS2 window; ANSSI 2024: €1.8M on FR DSP for inadequate ICT-risk-management evidence).

A single REST call to IP Geo API returns all four signal classes — country/region/subdivision/city/lat-lon, ASN + ASN-org-name (ISP vs hosting vs VPN-provider vs residential-proxy vs bulletproof-hosting classification), threat-flags (VPN/proxy/Tor/hosting/relay), risk score — on every plan, no add-on SKU, ≤40 ms median in EU.

What cybersecurity-ops buyers care about (in order)

  1. Log-ingest latency budget ≤ 40 ms. Every SIEM correlation rule, every IAM authentication, every EDR alert triage, and every SOAR playbook step must complete the IP-resolve inside the streaming-ingest budget (≤ 50 ms aggregate per pipeline stage to keep up with 10K-100K events/sec from a mid-size SOC) and inside the IAM authentication budget (≤ 200 ms before downstream OAuth/SAML/OIDC token issued — IP-geo is one signal among ~10 in the risk-engine). IP Geo API runs on EU edges (Hetzner Frankfurt) for ≤ 30-40 ms median across DE/NL/FR/IE/ES/IT/UK, ≤ 60 ms US-EU round-trip — well under the streaming-ingest budget and well under the IAM risk-engine budget (Okta ThreatInsight + Entra ID Identity Protection both run at ≤ 100 ms p99).
  2. NIS2 + DORA + SOC 2 + ISO 27001 + CMMC audit-trail evidence-log bundle. NIS2 Art. 21 risk-management + Art. 23 incident-notification require deterministic-replay of the IP-evidence + ASN-evidence + threat-fields-evidence at decision-time; DORA Art. 5-14 ICT-risk + Art. 28-44 third-party-ICT-risk require the same; SOC 2 Type II CC6.1 + CC7.2 + CC8.1 require audit-trail completeness (auditor walks the evidence sample); ISO 27001:2022 A.8.16 monitoring activities + A.8.20 networks security require IP-evidence retention; CMMC 2.0 Level 2 (NIST SP 800-171 §3.3 + §3.6 + §3.13) requires per-event source-IP attribution; EU CRA Art. 11 vulnerability handling + Art. 14 active-exploitation 24h-notification requires the same. IP Geo API ships a deterministic-replay log-format on every paid tier — same country_code + subdivision_iso_code + asn + asn_org_name + is_vpn/is_proxy/is_tor/is_hosting + risk_score at lookup-time gets persisted in the response envelope for audit-grade reconstruction by your compliance + regulator-notification + cyber-insurance + audit team.
  3. Threat fields on every plan, not a paid add-on. Most US incumbents (MaxMind, ipinfo.io, ipstack) split datacenter/VPN/proxy/Tor classification into a paid Security Module or Privacy add-on — a problem for cybersecurity-ops where 100% of high-severity alerts (C2 egress, credential stuffing, residential-proxy admin auth, Tor-exit privilege escalation) trace to specific threat-field classes on the source IP. IP Geo API ships is_vpn, is_proxy, is_tor, is_hosting, is_relay, and a numeric risk_score on the free tier — critical for SIEM correlation rules at log-ingest, EDR/XDR triage, IAM zero-trust step-up, and SOAR playbook gating.
  4. ASN-org-name + ASN-classification granularity for hosting vs ISP vs VPN-provider vs residential-proxy vs bulletproof-hosting routing. Country-only checks miss the hosting-vs-residential-proxy-vs-bulletproof-hosting distinction critical to triage decisions. A consumer authentication from Comcast AS7922 / Deutsche Telekom AS3320 / BT AS2856 is normal; the same auth from Bright Data AS207990 or DDoS-Guard AS262254 is impossible-topology. We expose asn + asn_org_name + asn_type (isp / business / hosting / mobile / cdn) on every paid tier — exactly what SIEM correlation rules + EDR detection content (Sigma rules, YARA-L, Splunk SPL, Elastic EQL, KQL, Chronicle YARA-L) consume to discriminate legitimate cloud egress from C2/exfil.
  5. EU residency + GDPR + ePrivacy + NIS2 + DORA posture. Security telemetry IPs are personal-data under GDPR Art. 4(1) + Recital 30 (IP is identifier); cannot be transferred to a US vendor without GDPR §28 DPA + SCCs + TIA (Schrems II); NIS2 Art. 21 requires national-CSIRT-grade evidence retention; DORA Art. 28 requires third-party-ICT-risk-assessment of the IP-geo vendor itself. The entire chain (IP-resolve, SIEM enrichment, IAM risk evaluation, EDR triage, SOAR action, regulator notification) must be EU-data-residency end-to-end for EU-entity events. IP Geo API is EU-only data-flow, signed DPA in 24h, no SCCs required, NIS2 + DORA third-party-ICT-risk-assessment one-pager included.

The four cybersecurity-ops control surfaces, in code

1. SOC/SIEM event-enrichment + threat-intel correlation at log-ingest (hard-fail-closed)

// /api/siem/enrich.js — Node 20 / streaming log-ingest, ≤40 ms hard budget per event
// Source IP → country + ASN + threat-fields → SIEM correlation severity boost.
const fetch = require('undici').fetch;

// Known residential-proxy ASN allowlist for "impossible-topology" detection
const RESIDENTIAL_PROXY_ASN = new Set([
  '207990', // Bright Data
  '44946',  // Oxylabs
  '133752', // Smartproxy
  '208045', // IPRoyal
  '61317',  // NetNut
  '398465', // SOAX
  '199524', // Geosurf
]);

// Known bulletproof-hosting ASN (per Mandiant 2024 + Recorded Future)
const BULLETPROOF_HOSTING_ASN = new Set([
  '262254', // DDoS-Guard
  '210848', // 1337team
  '44724',  // King Servers
  '197695', // FBW Networks SAS
  '209605', // QuickPacket
  '49981',  // WorldStream
]);

// Sanctioned country origin → hard-stop + OFAC team escalation
const SANCTIONED_COUNTRIES = new Set(['RU','BY','IR','KP','SY','CU','MM','SD','SO','IQ']);

async function enrichEvent(evt) {
  const ip = evt.source_ip;
  let geo;
  try {
    geo = await (await fetch(`https://ipgeo.10b.app/v1/${ip}?fields=country_code,subdivision_iso_code,asn,asn_org_name,asn_type,is_vpn,is_proxy,is_tor,is_hosting,is_relay,risk_score`, {
      headers: { 'Authorization': `Bearer ${process.env.IPGEO_KEY}` },
      signal: AbortSignal.timeout(40)
    })).json();
  } catch {
    return { ...evt, enrichment_status: 'geo_timeout', severity_boost: 0 };
  }

  let severityBoost = 0;
  const reasons = [];

  // Sanctioned country → P1 + OFAC escalation
  if (SANCTIONED_COUNTRIES.has(geo.country_code)) {
    severityBoost += 80;
    reasons.push(`sanctioned_country_${geo.country_code}`);
  }

  // Tor exit on sensitive resource → high-severity
  if (geo.is_tor && evt.resource_sensitivity === 'high') {
    severityBoost += 60;
    reasons.push('tor_exit_on_sensitive_resource');
  }

  // Residential-proxy ASN + admin-credential use → impossible topology
  if (RESIDENTIAL_PROXY_ASN.has(geo.asn) && evt.principal_role === 'admin') {
    severityBoost += 70;
    reasons.push(`residential_proxy_admin_auth_asn_${geo.asn}_${geo.asn_org_name}`);
  }

  // Bulletproof-hosting ASN → P1 (no legitimate use case)
  if (BULLETPROOF_HOSTING_ASN.has(geo.asn)) {
    severityBoost += 75;
    reasons.push(`bulletproof_hosting_asn_${geo.asn}_${geo.asn_org_name}`);
  }

  // Hosting ASN on consumer endpoint → likely bot/scanner
  if (geo.is_hosting && evt.endpoint_class === 'consumer') {
    severityBoost += 30;
    reasons.push('hosting_asn_consumer_endpoint');
  }

  return {
    ...evt,
    geo,
    severity_boost: severityBoost,
    enrichment_reasons: reasons,
    nis2_notification_clock: severityBoost >= 70 ? '24h_early_warning_started' : null,
  };
}

module.exports = { enrichEvent };

2. Zero-trust IAM step-up + impossible-travel + ASN-flip at authentication

# /api/iam/auth-risk.py — FastAPI, ≤200 ms IAM risk-engine budget, IP-geo is one signal
# Impossible-travel + ASN-flip + residential-proxy admin = step-up signals
import os, httpx, math
from fastapi import HTTPException

# Known VPN-provider ASN (subset, full list ~200 ASNs from MaxMind GeoIP2-Anonymous + ipinfo.io privacy_detection_database)
VPN_PROVIDER_ASN = {'9009','60068','396982','46562','51852','60781','42473'}

# Geodesic distance threshold for impossible-travel: km/h floor on commercial flight
MAX_GROUND_SPEED_KMH = 950  # commercial-aviation upper bound

def haversine_km(lat1, lon1, lat2, lon2):
    R = 6371
    p1, p2 = math.radians(lat1), math.radians(lat2)
    dp, dl = math.radians(lat2 - lat1), math.radians(lon2 - lon1)
    a = math.sin(dp/2)**2 + math.cos(p1) * math.cos(p2) * math.sin(dl/2)**2
    return 2 * R * math.asin(math.sqrt(a))

async def evaluate_auth_risk(user_id: str, ip: str, prior_session: dict):
    async with httpx.AsyncClient(timeout=0.04) as client:
        try:
            r = await client.get(
                f"https://ipgeo.10b.app/v1/{ip}",
                params={'fields': 'country_code,subdivision_iso_code,latitude,longitude,asn,asn_org_name,asn_type,is_vpn,is_proxy,is_tor,is_hosting,risk_score'},
                headers={'Authorization': f"Bearer {os.environ['IPGEO_KEY']}"}
            )
            geo = r.json()
        except Exception:
            return {'decision': 'allow_with_step_up', 'reason': 'geo_timeout_default_step_up'}

    # Hosting ASN on user credential auth → reject + force password reset
    if geo.get('is_hosting'):
        return {'decision': 'reject_force_pwd_reset', 'reason': f"hosting_asn_{geo.get('asn')}_{geo.get('asn_org_name')}_credential_leak_suspect"}

    # Tor exit → reject
    if geo.get('is_tor'):
        return {'decision': 'reject_tor_exit', 'reason': 'tor_exit_no_legitimate_use'}

    # Impossible travel: prior-session geo vs current-session geo
    if prior_session and prior_session.get('latitude'):
        dist_km = haversine_km(
            prior_session['latitude'], prior_session['longitude'],
            geo.get('latitude', 0), geo.get('longitude', 0)
        )
        elapsed_h = max(0.001, (prior_session['ts_now'] - prior_session['ts_prior']) / 3600)
        speed_kmh = dist_km / elapsed_h
        if speed_kmh > MAX_GROUND_SPEED_KMH:
            return {'decision': 'step_up_phishing_resistant_mfa', 'reason': f"impossible_travel_{dist_km:.0f}km_{elapsed_h:.2f}h_speed_{speed_kmh:.0f}kmh"}

    # ASN-flip + VPN classification → step-up
    if prior_session and prior_session.get('asn') and prior_session['asn'] != geo.get('asn'):
        if geo.get('is_vpn') or geo.get('asn') in VPN_PROVIDER_ASN:
            return {'decision': 'step_up_mfa', 'reason': f"asn_flip_prior_{prior_session['asn']}_now_{geo.get('asn')}_vpn"}

    return {'decision': 'allow', 'risk_score': geo.get('risk_score', 0), 'evidence': geo}

3. EDR/XDR alert triage + C2 egress detection via ASN-classification

// /api/edr/triage.js — invoked per EDR/XDR outbound-TLS alert
// Hosting + bulletproof + JA3-Cobalt-Strike + foreign-region → C2 alert
const fetch = require('undici').fetch;

const KNOWN_C2_INFRASTRUCTURE_ASN = new Set([
  '262254','210848','44724','197695','209605','49981', // bulletproof
  '20473', // Vultr (frequent abuse — flag, not block)
  '14061', // DigitalOcean (frequent abuse — flag, not block)
]);

const COBALT_STRIKE_JA3_HASHES = new Set([
  'a0e9f5d64349fb13191bc781f81f42e1',
  'b386946a5a44d1ddcc843bc75336dfce',
  '72a589da586844d7f0818ce684948eea',
]);

async function triageEgressAlert(alert) {
  const { destination_ip, ja3_hash, process_name, business_region } = alert;
  let geo;
  try {
    geo = await (await fetch(`https://ipgeo.10b.app/v1/${destination_ip}?fields=country_code,asn,asn_org_name,asn_type,is_hosting,is_vpn,is_proxy,is_tor,is_relay,risk_score`, {
      headers: { 'Authorization': `Bearer ${process.env.IPGEO_KEY}` },
      signal: AbortSignal.timeout(40)
    })).json();
  } catch {
    return { verdict: 'queue_manual_review', reason: 'geo_timeout' };
  }

  // Bulletproof-hosting destination → auto-isolate via EDR Network Containment
  if (KNOWN_C2_INFRASTRUCTURE_ASN.has(geo.asn)) {
    return {
      verdict: 'auto_isolate_endpoint',
      action: 'edr_network_containment',
      reason: `c2_infrastructure_asn_${geo.asn}_${geo.asn_org_name}`,
      mitre: 'T1071.001',
      severity: 'P1',
    };
  }

  // Cobalt Strike JA3 + hosting destination outside business region → P1
  if (COBALT_STRIKE_JA3_HASHES.has(ja3_hash) && geo.is_hosting && geo.country_code !== business_region) {
    return {
      verdict: 'auto_isolate_endpoint',
      action: 'edr_network_containment',
      reason: `cobalt_strike_ja3_${ja3_hash}_hosting_${geo.country_code}_outside_${business_region}`,
      mitre: 'T1071.001 + T1573',
      severity: 'P1',
    };
  }

  // LOLBin + hosting destination → block on detection
  const LOLBINS = ['powershell.exe', 'certutil.exe', 'bitsadmin.exe', 'msbuild.exe', 'mshta.exe', 'rundll32.exe'];
  if (LOLBINS.includes(process_name) && geo.is_hosting) {
    return {
      verdict: 'block_on_detection',
      action: 'edr_terminate_process_chain',
      reason: `lolbin_${process_name}_hosting_egress_${geo.asn_org_name}`,
      mitre: 'T1218 + T1071.001',
      severity: 'P2',
    };
  }

  // Outbound to VPN/proxy/Tor from workstation → DLP/exfil suspect
  if (geo.is_vpn || geo.is_proxy || geo.is_tor) {
    return {
      verdict: 'dlp_exfil_suspect',
      action: 'enqueue_dlp_inspection',
      reason: `anonymising_relay_${geo.asn}_${geo.asn_org_name}`,
      mitre: 'T1090.002',
      severity: 'P2',
    };
  }

  return { verdict: 'benign', evidence: geo };
}

module.exports = { triageEgressAlert };

4. NIS2 + DORA + SOC 2 + ISO 27001 + CMMC jurisdiction routing at audit-trail termination

# /api/audit/route-notification.py — routes incident notification to correct national CSIRT + regulator
# Per-jurisdiction notification clock + statute; VPN/proxy/Tor → highest-protection fallback
import os, httpx

NOTIFICATION_SHARD_MAP = {
    'DE': {'csirt': 'BSI Meldepflicht', 'statute': 'NIS2 transposed via BSIG §8b', 'window_h': 24, 'final_report_d': 30},
    'FR': {'csirt': 'ANSSI signalement', 'statute': 'NIS2 transposed via LPM 2018-607', 'window_h': 24, 'final_report_d': 30},
    'NL': {'csirt': 'NCSC-NL meldplicht', 'statute': 'Wbni + Wnbcb', 'window_h': 24, 'final_report_d': 30},
    'IT': {'csirt': 'ACN segnalazione', 'statute': 'D.lgs. 138/2024 (NIS2 transposition)', 'window_h': 24, 'final_report_d': 30},
    'IE': {'csirt': 'NCSC-IE notification', 'statute': 'NIS2 transposed via S.I. No. 360/2018', 'window_h': 24, 'final_report_d': 30},
    'AT': {'csirt': 'GovCERT.gv.at', 'statute': 'NISG 2018 + NIS2 amendment', 'window_h': 24, 'final_report_d': 30},
    'ES': {'csirt': 'CCN-CERT', 'statute': 'RD-Ley 7/2022 + NIS2', 'window_h': 24, 'final_report_d': 30},
    'PL': {'csirt': 'CERT.PL + CSIRT NASK', 'statute': 'UoKSC + NIS2', 'window_h': 24, 'final_report_d': 30},
    'BE': {'csirt': 'CCB notify', 'statute': 'NIS-wet + NIS2', 'window_h': 24, 'final_report_d': 30},
    'UK': {'csirt': 'NCSC + ICO 72h', 'statute': 'NIS Regs 2018 + UK GDPR Art. 33', 'window_h': 72, 'final_report_d': 30},
    'US': {'csirt': 'CISA + sector-ISAC', 'statute': 'CIRCIA 2022 + sector-specific (FS-ISAC, H-ISAC)', 'window_h': 72, 'final_report_d': 60},
    'IN': {'csirt': 'CERT-In', 'statute': 'CERT-In Directions Apr 2022', 'window_h': 6, 'final_report_d': 30},
    'AU': {'csirt': 'ACSC', 'statute': 'SOCI Act 2018 + Privacy Act NDB', 'window_h': 72, 'final_report_d': 30},
    'JP': {'csirt': 'NISC + JPCERT/CC', 'statute': 'Cybersecurity Basic Act', 'window_h': 72, 'final_report_d': 30},
}
FALLBACK_SHARD = NOTIFICATION_SHARD_MAP['DE']  # highest NIS2 + GDPR protection

DORA_APPLIES = {'AT','BE','BG','CY','CZ','DE','DK','EE','EL','ES','FI','FR','HR','HU','IE','IT','LT','LU','LV','MT','NL','PL','PT','RO','SE','SI','SK'}

async def route_incident_notification(source_ip: str, entity_country: str, severity: str, sector: str):
    async with httpx.AsyncClient(timeout=0.04) as client:
        try:
            r = await client.get(
                f"https://ipgeo.10b.app/v1/{source_ip}",
                params={'fields': 'country_code,subdivision_iso_code,is_vpn,is_proxy,is_tor,risk_score'},
                headers={'Authorization': f"Bearer {os.environ['IPGEO_KEY']}"}
            )
            geo = r.json()
        except Exception:
            return {'shard': FALLBACK_SHARD, 'reason': 'geo_timeout_highest_protection_fallback'}

    # Entity-of-record country governs notification; source-IP country adds attribution context
    target = NOTIFICATION_SHARD_MAP.get(entity_country, FALLBACK_SHARD)

    # DORA additional 4h major-incident notification for financial-sector EU entities
    extras = []
    if entity_country in DORA_APPLIES and sector in {'banking','payments','crypto-asset','investment','insurance','market-infrastructure'}:
        extras.append({'regime': 'DORA', 'window_h': 4, 'statute': 'Regulation (EU) 2022/2554 Art. 19'})

    # VPN/proxy/Tor source-IP → manual attribution-eval flag, not auto-attribution
    if geo.get('is_vpn') or geo.get('is_proxy') or geo.get('is_tor'):
        extras.append({'attribution_flag': 'anonymised_origin_manual_eval_required'})

    return {
        'primary_csirt': target['csirt'],
        'statute': target['statute'],
        'early_warning_window_h': target['window_h'],
        'final_report_window_d': target['final_report_d'],
        'extras': extras,
        'evidence': {
            'source_ip_country': geo.get('country_code'),
            'entity_country': entity_country,
            'sector': sector,
            'audit_log_retention_required': True,
        }
    }

Why the IP Geo API is purpose-built for cybersecurity ops

How to migrate from your incumbent — drop-in code-level guides

Already on an incumbent? These step-by-step migration guides ship with field-by-field maps, code diffs, shadow-mode validation, and rollback notes:

Industry deep-dives

Other vertical-specific surfaces using the same IP Geo API primitives:


Get started — cybersecurity-ops procurement

Sign up at https://ipgeo.10b.app/pricing and start with a sandbox key today.


Get early access — 50% off for 12 months

First 100 signups lock in 50% off any paid plan for the first year. No credit card required — we’ll email you at launch.