Security Guide • 13 min read

Bot Detection & Credential Stuffing Prevention with IP Intelligence

By Michael Torres, Security ArchitectUpdated January 2026

Automated bot attacks and credential stuffing cost enterprises $2.8M annually on average. This technical guide shows you how to implement IP-based bot detection, real-time filtering, and credential stuffing prevention using geolocation intelligence and reputation scoring.

Attack Prevention Metrics

97.3%
Bot Blocking Rate
Automated traffic filtered
8ms
Detection Time
Real-time classification
0.01%
False Positive Rate
Legitimate users blocked
2.8M
Annual Savings
Average prevented loss

The Threat Landscape

Credential stuffing attacks increased 273% in 2025, with botnets automating login attempts across thousands of compromised IP addresses. IP intelligence provides the most reliable signal for detecting automated attacks before they reach your authentication systems, blocking 97%+ of bot traffic with minimal user impact.

Understanding Automated Bot Attack Patterns

Bot attacks follow predictable patterns that IP intelligence can identify. Understanding these attack vectors is critical for designing effective defenses.

Credential Stuffing

Attackers automate login attempts using username/password pairs from previous data breaches across multiple websites.

High-velocity login attempts from single IP
Distributed attacks using proxy networks
Sequential attempts on leaked credential lists
IP Detection Signal:

Rapid login attempts from hosting providers, datacenter IPs, or residential proxy services with inconsistent geolocation patterns.

Account Enumeration

Bots systematically test usernames, email addresses, or phone numbers to identify valid accounts for targeted attacks.

Password reset form probing
Registration form validation testing
API endpoint discovery attempts
IP Detection Signal:

Systematic form submissions from automated sources, repetitive timing patterns, and requests originating from known botnet infrastructure.

Credential Spraying

Low-and-slow attacks that try a few common passwords across many accounts to avoid rate limiting and detection.

Common passwords across many accounts
Extended time periods (days/weeks)
Distributed IP rotation
IP Detection Signal:

Correlation of failed login attempts across unrelated accounts from the same ASN or IP prefix, with patterns indicating automated testing.

Automated Scraping

Bots systematically harvest content, pricing data, or user information from your platforms at scale.

High request rates to specific endpoints
Ignoring robots.txt directives
Lack of JavaScript execution
IP Detection Signal:

Requests from cloud hosting providers, absence of browser headers, and access patterns indicating systematic content retrieval.

IP-Based Bot Detection Methods

IP intelligence provides multiple orthogonal signals for bot detection. Combining these methods creates a robust defense system that adapts to evolving attack patterns.

1. Infrastructure Classification

Bots typically operate from hosting providers, datacenters, or cloud infrastructure rather than residential networks. Identifying connection types provides the strongest bot signal.

// Infrastructure-based bot detection
async function detectInfrastructureBot(
  ipAddress: string
): Promise<BotSignal> {
  const ipData = await ipInfoClient.security(ip);

  const signals = {
    isDatacenter: ipData.connection_type === 'hosting',
    isCloudProvider: [
      'amazon', 'google', 'microsoft', 'digitalocean',
      'linode', 'vultr', 'hetzner', 'ovh'
    ].some(provider =>
      ipData.isp.toLowerCase().includes(provider)
    ),
    isVPS: ipData.is_vps,
    isTor: ipData.is_tor,
    isHosting: ipData.is_hosting
  };

  // Calculate bot probability
  let botScore = 0;
  if (signals.isDatacenter) botScore += 0.6;
  if (signals.isCloudProvider) botScore += 0.3;
  if (signals.isVPS) botScore += 0.4;
  if (signals.isTor) botScore += 0.8;

  return {
    isBot: botScore > 0.5,
    confidence: Math.min(botScore, 1.0),
    signals
  };
}
High Risk

Datacenter, cloud, VPS infrastructure

Medium Risk

Hosting providers, business networks

Low Risk

Residential broadband, mobile networks

2. IP Reputation Scoring

Aggregate historical behavior data to build reputation scores for IP prefixes and ASNs. Known botnet infrastructure receives low scores, flagging requests for additional scrutiny.

// IP reputation scoring
interface IPReputation {
  score: number; // 0-100, higher is better
  risk: 'low' | 'medium' | 'high' | 'critical';
  factors: ReputationFactor[];
}

async function calculateIPReputation(
  ipAddress: string,
  asn: number,
  ipPrefix: string
): Promise<IPReputation> {
  const factors: ReputationFactor[] = [];

  // Historical fraud rate for this ASN
  const asnFraudRate = await reputationDB.getASNRate(asn);
  factors.push({
    name: 'asn_fraud_history',
    impact: asnFraudRate > 0.05 ? -30 : 0,
    value: asnFraudRate
  });

  // Recent bot activity from this /24 prefix
  const prefixBotRate = await reputationDB.getPrefixBotRate(ipPrefix);
  factors.push({
    name: 'prefix_bot_activity',
    impact: prefixBotRate > 0.1 ? -40 : 0,
    value: prefixBotRate
  });

  // Age of IP allocation (new IPs more suspicious)
  const ipAge = await ipInfoDB.getAllocationAge(ipPrefix);
  factors.push({
    name: 'ip_allocation_age',
    impact: ipAge < 30 ? -20 : 10,
    value: ipAge
  });

  // Calculate aggregate score
  const baseScore = 80;
  const totalImpact = factors.reduce((sum, f) => sum + f.impact, 0);
  const finalScore = Math.max(0, Math.min(100, baseScore + totalImpact));

  return {
    score: finalScore,
    risk: finalScore > 70 ? 'low' :
          finalScore > 50 ? 'medium' :
          finalScore > 30 ? 'high' : 'critical',
    factors
  };
}

3. Behavioral Pattern Analysis

Analyze request patterns across IP addresses to identify automated behavior. Bots exhibit distinct timing, sequencing, and correlation patterns that differ from human users.

// Behavioral bot detection
interface BehaviorScore {
  isAutomated: boolean;
  confidence: number;
  signals: string[];
}

function analyzeRequestBehavior(
  ipRequests: Request[]
): BehaviorScore {
  const signals: string[] = [];
  let confidence = 0;

  // Check for robotic timing patterns
  const intervals = calculateIntervals(ipRequests);
  const coefficient = stdDev(intervals) / mean(intervals);

  if (coefficient < 0.1) {
    signals.push('constant_timing_highly_suspicious');
    confidence += 0.4;
  }

  // Check for sequential user IDs/emails
  if (detectSequentialTargets(ipRequests)) {
    signals.push('sequential_account_targeting');
    confidence += 0.3;
  }

  // Check for identical user-agent strings
  const uniqueAgents = new Set(
    ipRequests.map(r => r.userAgent)
  ).size;

  if (uniqueAgents === 1 && ipRequests.length > 10) {
    signals.push('identical_user_agents');
    confidence += 0.2;
  }

  // Check for form submission without page views
  const formSubmissions = ipRequests.filter(
    r => r.method === 'POST'
  ).length;

  const pageViews = ipRequests.filter(
    r => r.method === 'GET' && r.isPageView
  ).length;

  if (formSubmissions > 5 && pageViews === 0) {
    signals.push('form_submission_without_browse');
    confidence += 0.3;
  }

  return {
    isAutomated: confidence > 0.5,
    confidence: Math.min(confidence, 1.0),
    signals
  };
}

4. Proxy and VPN Detection

Sophisticated bot operators route attacks through proxy networks to bypass IP-based blocking. Modern detection identifies both commercial VPN services and residential proxy infrastructures.

// Proxy and VPN detection
async function detectProxyInfrastructure(
  ipAddress: string
): Promise<ProxyDetection> {
  const [geoData, securityData] = await Promise.all([
    ipInfoClient.geolocation(ipAddress),
    ipInfoClient.security(ipAddress)
  ]);

  const detection = {
    isProxy: securityData.is_proxy,
    proxyType: securityData.proxy_type, // 'vpn', 'tor', 'residential', 'datacenter'
    isResidentialProxy: false,
    proxyScore: 0
  };

  // Residential proxy detection
  // (ISP claims residential but hosting detected)
  if (geoData.connection_type === 'isp' &&
      securityData.is_hosting) {
    detection.isResidentialProxy = true;
    detection.proxyScore += 0.7;
  }

  // Commercial VPN detection
  if (securityData.is_vpn) {
    detection.proxyScore += 0.5;

    // Check against known VPN exit nodes
    const isKnownVPN = await vpnDB.checkExitNode(ipAddress);
    if (isKnownVPN) {
      detection.proxyScore += 0.3;
    }
  }

  // Tor network detection
  if (securityData.is_tor) {
    detection.proxyScore += 0.9;
  }

  // Datacenter proxy detection
  if (securityData.is_hosting && !securityData.is_mobile) {
    detection.proxyScore += 0.6;
  }

  return {
    ...detection,
    isProxy: detection.proxyScore > 0.4,
    confidence: Math.min(detection.proxyScore, 1.0)
  };
}

Real-Time Bot Detection Architecture

Production bot detection requires multi-layered architecture that filters traffic before it reaches critical systems. Here is the proven pattern for high-scale platforms.

Multi-Layer Bot Filtering Pipeline

Incoming Request
All traffic
IP Reputation Filter
Block known bad IPs
Infrastructure Check
Flag hosting/VPN
Behavior Analysis
Pattern detection
Block
15% of traffic
Challenge
5% of traffic
Allow
80% of traffic
Total processing time: <10ms (P95) | Block rate: 15% | Challenge rate: 5%

Implementation Example: Middleware Filter

// Express/Next.js middleware for bot detection
import { LRUCache } from 'lru-cache';

const ipCache = new LRUCache<string, BotDecision>({
  max: 10000,
  ttl: 1000 * 60 * 5, // 5 minutes
});

export async function botDetectionMiddleware(
  req: Request,
  res: Response,
  next: NextFunction
) {
  const clientIP = getClientIP(req);
  const userAgent = req.headers['user-agent'];

  // Check cache first
  const cached = ipCache.get(clientIP);
  if (cached) {
    return handleDecision(cached, req, res, next);
  }

  // Parallel IP intelligence fetch
  const [geoData, securityData, reputation] = await Promise.all([
    ipInfoClient.geolocation(clientIP),
    ipInfoClient.security(clientIP),
    reputationService.score(clientIP)
  ]);

  // Layer 1: Hard block (known bad actors)
  if (reputation.score < 30) {
    const decision: BotDecision = {
      action: 'block',
      reason: 'known_malicious_ip',
      ttl: 3600
    };
    ipCache.set(clientIP, decision);
    return handleDecision(decision, req, res, next);
  }

  // Layer 2: Infrastructure filtering
  if (securityData.is_hosting || securityData.is_tor) {
    // For sensitive endpoints, block; others challenge
    const isSensitiveEndpoint =
      req.path.includes('/login') ||
      req.path.includes('/api/auth');

    const decision: BotDecision = isSensitiveEndpoint ? {
      action: 'block',
      reason: 'hosting_infrastructure',
      ttl: 1800
    } : {
      action: 'challenge',
      reason: 'suspicious_infrastructure',
      ttl: 900
    };
    ipCache.set(clientIP, decision);
    return handleDecision(decision, req, res, next);
  }

  // Layer 3: Behavioral analysis (for tracked IPs)
  const ipHistory = await requestHistory.get(clientIP);
  if (ipHistory && ipHistory.length > 10) {
    const behavior = analyzeBehavior(ipHistory);
    if (behavior.isAutomated && behavior.confidence > 0.7) {
      const decision: BotDecision = {
        action: 'block',
        reason: 'automated_behavior_pattern',
        ttl: 3600
      };
      ipCache.set(clientIP, decision);
      return handleDecision(decision, req, res, next);
    }
  }

  // Layer 4: Rate limiting by IP
  const rateLimitStatus = await rateLimiter.check(clientIP);
  if (!rateLimitStatus.allowed) {
    const decision: BotDecision = {
      action: 'challenge',
      reason: 'rate_limit_exceeded',
      ttl: 600
    };
    ipCache.set(clientIP, decision);
    return handleDecision(decision, req, res, next);
  }

  // Passed all checks
  const decision: BotDecision = {
    action: 'allow',
    reason: 'all_checks_passed',
    ttl: 300
  };
  ipCache.set(clientIP, decision);
  return handleDecision(decision, req, res, next);
}

function handleDecision(
  decision: BotDecision,
  req: Request,
  res: Response,
  next: NextFunction
) {
  switch (decision.action) {
    case 'block':
      res.status(403).json({
        error: 'Access denied',
        message: 'Your request has been blocked.'
      });
      return;

    case 'challenge':
      // Redirect to CAPTCHA or JavaScript challenge
      res.redirect('/challenge?token=' + generateChallengeToken());
      return;

    case 'allow':
      // Track request for behavioral analysis
      requestHistory.track(getClientIP(req), {
        path: req.path,
        method: req.method,
        userAgent: req.headers['user-agent'],
        timestamp: Date.now()
      });
      next();
      return;
  }
}

Credential Stuffing Prevention Strategies

Credential stuffing attacks require specialized detection beyond general bot filtering. These attacks exploit compromised credentials from other breaches and require IP-aware authentication security.

Attack Pattern Recognition

Credential stuffing exhibits distinct IP-level patterns that differ from normal login behavior.

Single IP, multiple accounts: Sequential login attempts to different user accounts from one IP address
Distributed IPs, same passwords: Same password attempted across accounts from different IPs in same ASN
Proxy rotation: Rapid IP changes between attempts using residential proxy networks
Geographic inconsistency: Login attempts from locations inconsistent with user's historical patterns

IP-Aware Authentication Security

Strengthen authentication using IP intelligence without adding user friction.

Travel velocity checks: Flag logins from locations geographically impossible to reach from previous login
New location MFA: Require additional verification for logins from new countries or cities
IP-based risk scoring: Calculate login risk based on IP reputation, proxy status, and historical fraud
Temporary blocks: Block IPs with multiple failed login attempts across different accounts

Credential Stuffing Detection Implementation

// Credential stuffing detection service
class CredentialStuffingDetector {
  private redis: Redis;
  private ipInfo: IPInfoClient;

  async checkLoginAttempt(
    username: string,
    password: string, // hashed
    ipAddress: string,
    userAgent: string
  ): Promise<LoginDecision> {
    const [ipData, failedAttempts] = await Promise.all([
      this.ipInfo.security(ipAddress),
      this.getRecentFailedLogins(ipAddress, 3600)
    ]);

    const riskFactors: RiskFactor[] = [];

    // Check 1: Multiple failed attempts from this IP
    const uniqueAccounts = new Set(
      failedAttempts.map(a => a.username)
    ).size;

    if (uniqueAccounts >= 5) {
      riskFactors.push({
        factor: 'multiple_account_attempts',
        weight: 0.8,
        description: `IP attempted logins to ${uniqueAccounts} accounts`
      });
    }

    // Check 2: Proxy/VPN usage
    if (ipData.is_proxy || ipData.is_vpn) {
      riskFactors.push({
        factor: 'proxy_infrastructure',
        weight: ipData.is_tor ? 0.9 : 0.5,
        description: 'Login from anonymous proxy network'
      });
    }

    // Check 3: Datacenter/hosting IP
    if (ipData.is_hosting) {
      riskFactors.push({
        factor: 'hosting_infrastructure',
        weight: 0.7,
        description: 'Login from datacenter IP'
      });
    }

    // Check 4: Geographic velocity (if user has history)
    const userHistory = await this.getUserLocationHistory(username);
    if (userHistory.lastLocation) {
      const velocity = this.calculateVelocity(
        userHistory.lastLocation,
        ipData.coordinates,
        userHistory.lastLoginTime
      );

      if (velocity > 900) { // Faster than commercial flight
        riskFactors.push({
          factor: 'impossible_travel',
          weight: 0.95,
          description: 'Impossible travel velocity detected'
        });
      }
    }

    // Calculate aggregate risk
    const totalRisk = riskFactors.reduce(
      (sum, factor) => Math.max(sum, factor.weight),
      0
    );

    // Make decision
    if (totalRisk >= 0.8) {
      return {
        allowed: false,
        reason: 'high_risk_credential_stuffing',
        requireMFA: false,
        blockIP: true,
        riskFactors
      };
    }

    if (totalRisk >= 0.5) {
      return {
        allowed: true,
        reason: 'medium_risk_require_verification',
        requireMFA: true,
        blockIP: false,
        riskFactors
      };
    }

    return {
      allowed: true,
      reason: 'normal_login',
      requireMFA: false,
      blockIP: false,
      riskFactors: []
    };
  }

  private async getRecentFailedLogins(
    ip: string,
    seconds: number
  ): Promise<FailedLogin[]> {
    const key = `failed_logins:${ip}`;
    const attempts = await this.redis.zrangebyscore(
      key,
      Date.now() - (seconds * 1000),
      Date.now()
    );
    return attempts.map(JSON.parse);
  }

  private calculateVelocity(
    from: Coordinates,
    to: Coordinates,
    timestampMs: number
  ): number {
    const distance = haversine(from, to); // km
    const hours = (Date.now() - timestampMs) / 3600000;
    return distance / hours; // km/h
  }
}

Real-World Implementation Results

MetricBefore IP DetectionAfter IP DetectionImprovement
Successful Account Takeovers247/month18/month-92.7%
Credential Stuffing Attempts2.3M/monthBlocked (97.3%)Prevented
False Positive RateN/A0.01%Minimal Impact
Average Detection LatencyPost-login only8ms (pre-login)Proactive
Support Tickets (Access Issues)Baseline+0.8%Negligible

Case Study: B2B SaaS Platform (50K Users)

Implemented IP-based bot detection and credential stuffing prevention in January 2025. Results measured over 6-month period showing 92.7% reduction in successful account takeovers while maintaining 0.01% false positive rate. System now blocks 2.2M credential stuffing attempts monthly before reaching authentication servers. Total implementation cost: $12K/month in IP API costs, preventing an estimated $2.8M in potential fraud losses.

Production Best Practices

Do This

  • Implement progressive challenges: Start with invisible checks, escalate to CAPTCHA only when necessary
  • Cache IP decisions: Store bot classifications for 5-15 minutes to reduce API calls and latency
  • Monitor false positives: Alert on legitimate users incorrectly flagged and whitelist their IPs
  • Rate limit by IP prefix: Block entire /24 or /32 subnets when attack patterns emerge
  • Log all decisions: Maintain audit trails for blocked requests to review and improve detection
  • Test in shadow mode: Run detection without blocking for 2 weeks to measure accuracy

Avoid This

  • Don't rely solely on IP: Combine with behavioral signals, device fingerprinting, and request patterns
  • Don't block legitimate VPNs: Many remote workers use corporate VPNs; whitelist known business ranges
  • Don't ignore mobile networks: Mobile IP addresses change frequently; use wider tolerance for cellular connections
  • Don't set block TTLs too long: Legitimate users may share IPs (NAT) or get recycled addresses
  • Don't forget geographic diversity: Adjust thresholds for regions with different network characteristics
  • Don't skip user communication: Tell users why they were challenged and how to resolve it

Stop Bot Attacks Before They Reach Your App

Get started with IP-based bot detection in under 10 minutes. Test with 1,000 free requests and see the difference.

Frequently Asked Questions

How accurate is IP-based bot detection?

IP-based detection achieves 97%+ accuracy when combining infrastructure classification, reputation scoring, and behavioral analysis. False positive rates typically stay below 0.01% when properly configured. The key is using multiple signals rather than relying on a single detection method.

Won't blocking datacenter IPs block legitimate users who work from cloud offices?

Yes, which is why smart implementations use challenge flows rather than hard blocks for datacenter IPs. Legitimate users can complete a CAPTCHA or JavaScript challenge, while automated bots cannot. For known corporate ranges, implement whitelisting based on ASN or organization name.

How do you handle bot attacks from residential proxy networks?

Residential proxies are detected by correlating IP behavior patterns across many requests. Look for: (1) rapid request rates inconsistent with human behavior, (2) lack of browser headers or JavaScript execution, (3) sequential targeting patterns, and (4) correlation with known proxy service IP ranges. Reputation databases also track identified residential proxy exit nodes.

What is the performance impact of IP-based bot detection on login latency?

With proper caching and parallel API calls, bot detection adds 5-15ms to request processing (P95). Cache hit rates typically exceed 80% for residential IPs, eliminating API calls for most legitimate users. The performance cost is minimal compared to the fraud prevention benefits.

Should I implement IP detection at CDN or application level?

Both. CDN-level filtering blocks known bad IPs and hosting infrastructure before requests reach your servers. Application-level detection handles more sophisticated analysis including behavioral patterns, credential stuffing detection, and user-specific risk scoring. The layered approach provides defense in depth.

Related Articles