DDoS Protection for ChatGPT Apps: Production Security Guide

Distributed Denial of Service (DDoS) attacks represent one of the most serious threats to ChatGPT applications. As your app gains traction with OpenAI's 800 million weekly users, it becomes an increasingly attractive target for attackers seeking to overwhelm your infrastructure, exhaust API quotas, or cause service disruption. A successful DDoS attack can result in complete service outages, degraded user experience, excessive cloud costs from auto-scaling, and potential violation of OpenAI's rate limit policies leading to app suspension.

DDoS attacks against ChatGPT apps come in three primary forms: volumetric attacks that flood your network with massive traffic volumes, application-layer attacks that target your MCP server endpoints with seemingly legitimate requests, and API exhaustion attacks that deliberately consume your OpenAI API quotas. Traditional web applications face bandwidth saturation, but ChatGPT apps have the additional vulnerability of expensive API calls—each malicious request can cost real money in OpenAI usage fees.

Effective DDoS protection requires a defense-in-depth strategy with multiple coordinated layers: perimeter protection through CDN and Web Application Firewall (WAF), intelligent rate limiting at network and application tiers, infrastructure resilience through auto-scaling and circuit breakers, real-time traffic analysis for anomaly detection, and comprehensive incident response procedures. This guide provides production-ready implementations for each defensive layer, with battle-tested code examples you can deploy immediately to protect your ChatGPT application from DDoS threats.

CDN & WAF Integration: Perimeter Defense

Your first line of defense is a Content Delivery Network (CDN) with integrated Web Application Firewall (WAF) capabilities. Cloudflare, AWS CloudFront with AWS WAF, and Google Cloud Armor provide enterprise-grade DDoS protection that operates at the network edge, absorbing attacks before they reach your infrastructure.

Cloudflare Workers enable custom DDoS filtering logic that runs at the edge, inspecting every request before it touches your origin server. This Cloudflare Worker implements multi-factor DDoS detection with IP reputation scoring, request pattern analysis, and adaptive challenge issuance:

// cloudflare-workers/ddos-filter.ts
// Production Cloudflare Worker for DDoS protection
// Deploy: wrangler publish

interface RateLimitEntry {
  count: number;
  timestamp: number;
  score: number;
}

interface IPReputation {
  score: number;
  violations: number;
  lastViolation: number;
  blocked: boolean;
}

export default {
  async fetch(request: Request, env: any, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);
    const clientIP = request.headers.get('CF-Connecting-IP') || 'unknown';
    const userAgent = request.headers.get('User-Agent') || '';
    const country = request.headers.get('CF-IPCountry') || 'XX';

    // Check if IP is on blocklist (KV namespace)
    const blockedIP = await env.BLOCKED_IPS.get(clientIP);
    if (blockedIP) {
      return new Response('Access Denied', {
        status: 403,
        headers: {
          'X-Block-Reason': 'IP Blocklist',
          'Retry-After': '3600'
        }
      });
    }

    // Get IP reputation
    const reputationData = await env.IP_REPUTATION.get(clientIP);
    let reputation: IPReputation = reputationData
      ? JSON.parse(reputationData)
      : { score: 100, violations: 0, lastViolation: 0, blocked: false };

    // Suspicious request detection
    const suspicionScore = calculateSuspicionScore(request, userAgent, country);

    // Rate limiting check (KV namespace)
    const rateLimitKey = `ratelimit:${clientIP}`;
    const rateLimitData = await env.RATE_LIMITS.get(rateLimitKey);
    let rateLimit: RateLimitEntry = rateLimitData
      ? JSON.parse(rateLimitData)
      : { count: 0, timestamp: Date.now(), score: 0 };

    const now = Date.now();
    const windowMs = 60000; // 1 minute window

    // Reset window if expired
    if (now - rateLimit.timestamp > windowMs) {
      rateLimit = { count: 0, timestamp: now, score: 0 };
    }

    rateLimit.count++;
    rateLimit.score += suspicionScore;

    // Thresholds
    const MAX_REQUESTS_PER_MIN = 60;
    const MAX_SUSPICION_SCORE = 150;

    // Check if limits exceeded
    if (rateLimit.count > MAX_REQUESTS_PER_MIN || rateLimit.score > MAX_SUSPICION_SCORE) {
      reputation.violations++;
      reputation.lastViolation = now;
      reputation.score = Math.max(0, reputation.score - 20);

      // Update reputation
      await env.IP_REPUTATION.put(
        clientIP,
        JSON.stringify(reputation),
        { expirationTtl: 86400 }
      );

      // Progressive response based on violation history
      if (reputation.violations > 3) {
        // Block for 1 hour
        await env.BLOCKED_IPS.put(clientIP, 'auto-block', { expirationTtl: 3600 });
        return new Response('Too Many Requests - Blocked', {
          status: 429,
          headers: {
            'Retry-After': '3600',
            'X-Block-Reason': 'Repeated Violations'
          }
        });
      } else {
        // Issue CAPTCHA challenge
        return issueChallenge(request, env, 'rate-limit');
      }
    }

    // Check reputation score
    if (reputation.score < 30) {
      return issueChallenge(request, env, 'low-reputation');
    }

    // Update rate limit
    await env.RATE_LIMITS.put(
      rateLimitKey,
      JSON.stringify(rateLimit),
      { expirationTtl: 120 }
    );

    // Allow request to pass
    const response = await fetch(request);

    // Improve reputation on successful requests
    if (response.status < 400) {
      reputation.score = Math.min(100, reputation.score + 1);
      await env.IP_REPUTATION.put(
        clientIP,
        JSON.stringify(reputation),
        { expirationTtl: 86400 }
      );
    }

    return response;
  }
};

function calculateSuspicionScore(
  request: Request,
  userAgent: string,
  country: string
): number {
  let score = 0;
  const url = new URL(request.url);

  // Bot detection
  const botPatterns = [
    /bot/i, /crawler/i, /spider/i, /scraper/i,
    /curl/i, /wget/i, /python/i, /java/i
  ];
  if (botPatterns.some(pattern => pattern.test(userAgent))) {
    score += 30;
  }

  // Empty or suspicious user agent
  if (!userAgent || userAgent.length < 10) {
    score += 25;
  }

  // High-risk countries (customize based on your threat model)
  const highRiskCountries = ['XX', 'CN', 'RU', 'KP'];
  if (highRiskCountries.includes(country)) {
    score += 15;
  }

  // Suspicious URL patterns
  if (url.pathname.includes('..') || url.pathname.includes('admin')) {
    score += 40;
  }

  // HTTP method anomalies
  if (!['GET', 'POST', 'OPTIONS'].includes(request.method)) {
    score += 20;
  }

  // Missing common headers
  if (!request.headers.get('Accept') || !request.headers.get('Accept-Language')) {
    score += 10;
  }

  return score;
}

async function issueChallenge(
  request: Request,
  env: any,
  reason: string
): Promise<Response> {
  const html = `
    <!DOCTYPE html>
    <html>
    <head>
      <title>Security Challenge</title>
      <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
    </head>
    <body>
      <h1>Security Verification Required</h1>
      <p>Please complete this challenge to continue.</p>
      <form method="POST" action="/verify-challenge">
        <div class="cf-turnstile" data-sitekey="${env.TURNSTILE_SITE_KEY}"></div>
        <input type="hidden" name="reason" value="${reason}" />
        <button type="submit">Verify</button>
      </form>
    </body>
    </html>
  `;

  return new Response(html, {
    status: 403,
    headers: {
      'Content-Type': 'text/html',
      'X-Challenge-Reason': reason
    }
  });
}

Configure WAF rules to block common attack patterns. This AWS WAF configuration demonstrates rule groups for SQL injection, XSS, and rate-based blocking:

// infrastructure/waf-rules.ts
// AWS WAF Web ACL configuration for DDoS protection

import * as aws from '@pulumi/aws';

export function createWAFWebACL(name: string): aws.wafv2.WebAcl {
  return new aws.wafv2.WebAcl(name, {
    scope: 'CLOUDFRONT',
    defaultAction: { allow: {} },

    rules: [
      // AWS Managed Rules - Core Rule Set
      {
        name: 'AWSManagedRulesCommonRuleSet',
        priority: 1,
        statement: {
          managedRuleGroupStatement: {
            vendorName: 'AWS',
            name: 'AWSManagedRulesCommonRuleSet'
          }
        },
        overrideAction: { none: {} },
        visibilityConfig: {
          cloudwatchMetricsEnabled: true,
          metricName: 'AWSManagedRulesCommonRuleSetMetric',
          sampledRequestsEnabled: true
        }
      },

      // Rate-based rule - 2000 requests per 5 minutes per IP
      {
        name: 'RateLimitRule',
        priority: 2,
        statement: {
          rateBasedStatement: {
            limit: 2000,
            aggregateKeyType: 'IP'
          }
        },
        action: {
          block: {
            customResponse: {
              responseCode: 429,
              customResponseBodyKey: 'rate-limit-body'
            }
          }
        },
        visibilityConfig: {
          cloudwatchMetricsEnabled: true,
          metricName: 'RateLimitRuleMetric',
          sampledRequestsEnabled: true
        }
      },

      // Geo-blocking (optional - customize)
      {
        name: 'GeoBlockingRule',
        priority: 3,
        statement: {
          notStatement: {
            statement: {
              geoMatchStatement: {
                countryCodes: ['US', 'CA', 'GB', 'DE', 'FR', 'JP', 'AU']
              }
            }
          }
        },
        action: { block: {} },
        visibilityConfig: {
          cloudwatchMetricsEnabled: true,
          metricName: 'GeoBlockingRuleMetric',
          sampledRequestsEnabled: true
        }
      }
    ],

    visibilityConfig: {
      cloudwatchMetricsEnabled: true,
      metricName: 'ChatGPTAppWAFMetric',
      sampledRequestsEnabled: true
    }
  });
}

Multi-Layer Rate Limiting Defense

Application-layer rate limiting provides granular control beyond CDN-level throttling. Implement rate limiting at multiple tiers: IP-based limits, authenticated user limits, API endpoint limits, and OpenAI quota protection.

This production-ready rate limiter uses Redis for distributed state and implements token bucket algorithm with multiple limit tiers:

// src/middleware/rate-limiter.ts
// Multi-layer distributed rate limiter with Redis backend
// Supports: IP limits, user limits, endpoint limits, API quota protection

import { Request, Response, NextFunction } from 'express';
import Redis from 'ioredis';

interface RateLimitConfig {
  windowMs: number;
  maxRequests: number;
  skipSuccessfulRequests?: boolean;
  skipFailedRequests?: boolean;
  keyGenerator?: (req: Request) => string;
}

interface RateLimitTier {
  name: string;
  windowMs: number;
  maxRequests: number;
}

export class MultiLayerRateLimiter {
  private redis: Redis;
  private tiers: Map<string, RateLimitTier[]>;

  constructor(redisUrl: string) {
    this.redis = new Redis(redisUrl);
    this.tiers = new Map();

    // Define rate limit tiers
    this.defineDefaultTiers();
  }

  private defineDefaultTiers(): void {
    // IP-based limits (unauthenticated users)
    this.tiers.set('ip', [
      { name: 'second', windowMs: 1000, maxRequests: 10 },
      { name: 'minute', windowMs: 60000, maxRequests: 60 },
      { name: 'hour', windowMs: 3600000, maxRequests: 500 }
    ]);

    // Authenticated user limits
    this.tiers.set('user', [
      { name: 'second', windowMs: 1000, maxRequests: 20 },
      { name: 'minute', windowMs: 60000, maxRequests: 100 },
      { name: 'hour', windowMs: 3600000, maxRequests: 1000 }
    ]);

    // MCP tool call limits (protect OpenAI quota)
    this.tiers.set('mcp-tool', [
      { name: 'second', windowMs: 1000, maxRequests: 5 },
      { name: 'minute', windowMs: 60000, maxRequests: 30 },
      { name: 'hour', windowMs: 3600000, maxRequests: 200 }
    ]);

    // Admin endpoints (strict limits)
    this.tiers.set('admin', [
      { name: 'second', windowMs: 1000, maxRequests: 2 },
      { name: 'minute', windowMs: 60000, maxRequests: 10 },
      { name: 'hour', windowMs: 3600000, maxRequests: 50 }
    ]);
  }

  public middleware(tierName: string = 'ip'): (req: Request, res: Response, next: NextFunction) => Promise<void> {
    return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
      const tiers = this.tiers.get(tierName);
      if (!tiers) {
        return next();
      }

      const key = this.generateKey(req, tierName);

      try {
        // Check all tiers
        for (const tier of tiers) {
          const allowed = await this.checkLimit(key, tier);

          if (!allowed) {
            const retryAfter = Math.ceil(tier.windowMs / 1000);

            res.setHeader('X-RateLimit-Limit', tier.maxRequests.toString());
            res.setHeader('X-RateLimit-Remaining', '0');
            res.setHeader('X-RateLimit-Reset', (Date.now() + tier.windowMs).toString());
            res.setHeader('Retry-After', retryAfter.toString());

            res.status(429).json({
              error: 'Too Many Requests',
              message: `Rate limit exceeded. Try again in ${retryAfter} seconds.`,
              tier: tier.name,
              limit: tier.maxRequests,
              window: tier.windowMs
            });
            return;
          }
        }

        // Increment counters for all tiers
        await Promise.all(tiers.map(tier => this.incrementCounter(key, tier)));

        next();
      } catch (error) {
        console.error('Rate limiter error:', error);
        // Fail open - allow request if rate limiter fails
        next();
      }
    };
  }

  private generateKey(req: Request, tierName: string): string {
    const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress || 'unknown';
    const userId = (req as any).user?.uid || 'anonymous';
    const path = req.path;

    switch (tierName) {
      case 'user':
        return `ratelimit:user:${userId}`;
      case 'mcp-tool':
        return `ratelimit:mcp:${userId}:${path}`;
      case 'admin':
        return `ratelimit:admin:${userId}:${ip}`;
      default:
        return `ratelimit:ip:${ip}`;
    }
  }

  private async checkLimit(key: string, tier: RateLimitTier): Promise<boolean> {
    const tierKey = `${key}:${tier.name}`;
    const current = await this.redis.get(tierKey);

    if (!current) {
      return true;
    }

    const count = parseInt(current, 10);
    return count < tier.maxRequests;
  }

  private async incrementCounter(key: string, tier: RateLimitTier): Promise<void> {
    const tierKey = `${key}:${tier.name}`;
    const multi = this.redis.multi();

    multi.incr(tierKey);
    multi.pexpire(tierKey, tier.windowMs);

    await multi.exec();
  }

  public async resetLimit(identifier: string, tierName: string): Promise<void> {
    const pattern = `ratelimit:${tierName}:${identifier}:*`;
    const keys = await this.redis.keys(pattern);

    if (keys.length > 0) {
      await this.redis.del(...keys);
    }
  }

  public async getUsage(identifier: string, tierName: string): Promise<Record<string, number>> {
    const tiers = this.tiers.get(tierName);
    if (!tiers) return {};

    const key = tierName === 'ip'
      ? `ratelimit:ip:${identifier}`
      : `ratelimit:${tierName}:${identifier}`;

    const usage: Record<string, number> = {};

    for (const tier of tiers) {
      const tierKey = `${key}:${tier.name}`;
      const count = await this.redis.get(tierKey);
      usage[tier.name] = count ? parseInt(count, 10) : 0;
    }

    return usage;
  }
}

// Usage example
// const rateLimiter = new MultiLayerRateLimiter(process.env.REDIS_URL);
// app.use('/api', rateLimiter.middleware('ip'));
// app.use('/mcp', rateLimiter.middleware('mcp-tool'));

Implement CAPTCHA challenges for suspicious traffic patterns:

// src/middleware/captcha-challenge.ts
// Adaptive CAPTCHA challenge system with Cloudflare Turnstile

import { Request, Response, NextFunction } from 'express';
import axios from 'axios';

interface ChallengeConfig {
  threshold: number;
  enabled: boolean;
  siteKey: string;
  secretKey: string;
}

export class CaptchaChallenge {
  private config: ChallengeConfig;
  private suspicionScores: Map<string, number>;

  constructor(config: ChallengeConfig) {
    this.config = config;
    this.suspicionScores = new Map();
  }

  public middleware() {
    return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
      if (!this.config.enabled) {
        return next();
      }

      const ip = this.getClientIP(req);
      const suspicionScore = this.calculateSuspicionScore(req);

      // Update suspicion score
      const currentScore = this.suspicionScores.get(ip) || 0;
      const newScore = currentScore + suspicionScore;
      this.suspicionScores.set(ip, newScore);

      // Require CAPTCHA if threshold exceeded
      if (newScore > this.config.threshold) {
        const token = req.body['cf-turnstile-response'] || req.headers['x-captcha-token'];

        if (!token) {
          res.status(403).json({
            error: 'CAPTCHA Required',
            message: 'Please complete the CAPTCHA challenge',
            siteKey: this.config.siteKey,
            challenge: true
          });
          return;
        }

        // Verify CAPTCHA token
        const verified = await this.verifyCaptcha(token, ip);

        if (!verified) {
          res.status(403).json({
            error: 'CAPTCHA Verification Failed',
            message: 'Invalid CAPTCHA response',
            challenge: true
          });
          return;
        }

        // Reset suspicion score on successful verification
        this.suspicionScores.set(ip, 0);
      }

      next();
    };
  }

  private calculateSuspicionScore(req: Request): number {
    let score = 0;

    // User agent checks
    const userAgent = req.headers['user-agent'] || '';
    if (!userAgent || userAgent.length < 10) score += 30;
    if (/bot|crawler|spider/i.test(userAgent)) score += 25;

    // Method checks
    if (req.method !== 'GET' && req.method !== 'POST') score += 20;

    // Header checks
    if (!req.headers['accept']) score += 15;
    if (!req.headers['accept-language']) score += 10;

    // Path checks
    if (req.path.includes('admin') || req.path.includes('..')) score += 40;

    return score;
  }

  private async verifyCaptcha(token: string, ip: string): Promise<boolean> {
    try {
      const response = await axios.post(
        'https://challenges.cloudflare.com/turnstile/v0/siteverify',
        {
          secret: this.config.secretKey,
          response: token,
          remoteip: ip
        }
      );

      return response.data.success === true;
    } catch (error) {
      console.error('CAPTCHA verification error:', error);
      return false;
    }
  }

  private getClientIP(req: Request): string {
    return (req.headers['cf-connecting-ip'] ||
            req.headers['x-forwarded-for'] ||
            req.socket.remoteAddress ||
            'unknown') as string;
  }
}

Infrastructure Resilience: Auto-Scaling & Circuit Breakers

Infrastructure resilience ensures your ChatGPT app degrades gracefully under attack rather than failing completely. Auto-scaling responds to traffic spikes, load balancers distribute requests, and circuit breakers prevent cascade failures.

This Kubernetes Horizontal Pod Autoscaler configuration demonstrates auto-scaling based on CPU, memory, and custom metrics:

# infrastructure/k8s/autoscaling.yaml
# Kubernetes Horizontal Pod Autoscaler for MCP server
# Scales based on CPU, memory, and custom metrics

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: mcp-server-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: mcp-server
  minReplicas: 3
  maxReplicas: 50
  metrics:
    # CPU-based scaling
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

    # Memory-based scaling
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

    # Request rate (custom metric from Prometheus)
    - type: Pods
      pods:
        metric:
          name: http_requests_per_second
        target:
          type: AverageValue
          averageValue: "100"

    # Response time (custom metric)
    - type: Pods
      pods:
        metric:
          name: http_request_duration_p95
        target:
          type: AverageValue
          averageValue: "500m"  # 500ms

  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
        - type: Percent
          value: 100
          periodSeconds: 15
        - type: Pods
          value: 4
          periodSeconds: 15
      selectPolicy: Max

    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 50
          periodSeconds: 60
        - type: Pods
          value: 2
          periodSeconds: 60
      selectPolicy: Min

---
apiVersion: v1
kind: Service
metadata:
  name: mcp-server
  namespace: production
spec:
  selector:
    app: mcp-server
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
  type: LoadBalancer
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 300

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mcp-server
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mcp-server
  template:
    metadata:
      labels:
        app: mcp-server
    spec:
      containers:
        - name: mcp-server
          image: gcr.io/your-project/mcp-server:latest
          ports:
            - containerPort: 3000
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
            limits:
              cpu: 2000m
              memory: 2Gi
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /ready
              port: 3000
            initialDelaySeconds: 10
            periodSeconds: 5
          env:
            - name: OPENAI_API_KEY
              valueFrom:
                secretKeyRef:
                  name: openai-secrets
                  key: api-key
            - name: REDIS_URL
              valueFrom:
                configMapKeyRef:
                  name: app-config
                  key: redis-url
            - name: MAX_CONCURRENT_REQUESTS
              value: "100"

Circuit breaker implementation prevents cascade failures by failing fast when downstream services are unhealthy:

// src/utils/circuit-breaker.ts
// Circuit breaker pattern for external API calls (OpenAI, databases)

interface CircuitBreakerConfig {
  failureThreshold: number;
  successThreshold: number;
  timeout: number;
  resetTimeout: number;
}

enum CircuitState {
  CLOSED = 'CLOSED',
  OPEN = 'OPEN',
  HALF_OPEN = 'HALF_OPEN'
}

export class CircuitBreaker {
  private state: CircuitState = CircuitState.CLOSED;
  private failureCount: number = 0;
  private successCount: number = 0;
  private nextAttempt: number = Date.now();
  private config: CircuitBreakerConfig;

  constructor(config: Partial<CircuitBreakerConfig> = {}) {
    this.config = {
      failureThreshold: config.failureThreshold || 5,
      successThreshold: config.successThreshold || 2,
      timeout: config.timeout || 60000,
      resetTimeout: config.resetTimeout || 30000
    };
  }

  public async execute<T>(fn: () => Promise<T>): Promise<T> {
    if (this.state === CircuitState.OPEN) {
      if (Date.now() < this.nextAttempt) {
        throw new Error('Circuit breaker is OPEN');
      }
      this.state = CircuitState.HALF_OPEN;
    }

    try {
      const result = await this.executeWithTimeout(fn);
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  private async executeWithTimeout<T>(fn: () => Promise<T>): Promise<T> {
    return Promise.race([
      fn(),
      new Promise<T>((_, reject) =>
        setTimeout(() => reject(new Error('Request timeout')), this.config.timeout)
      )
    ]);
  }

  private onSuccess(): void {
    this.failureCount = 0;

    if (this.state === CircuitState.HALF_OPEN) {
      this.successCount++;
      if (this.successCount >= this.config.successThreshold) {
        this.state = CircuitState.CLOSED;
        this.successCount = 0;
      }
    }
  }

  private onFailure(): void {
    this.failureCount++;
    this.successCount = 0;

    if (this.failureCount >= this.config.failureThreshold) {
      this.state = CircuitState.OPEN;
      this.nextAttempt = Date.now() + this.config.resetTimeout;
    }
  }

  public getState(): CircuitState {
    return this.state;
  }

  public reset(): void {
    this.state = CircuitState.CLOSED;
    this.failureCount = 0;
    this.successCount = 0;
  }
}

Real-Time Traffic Analysis: Anomaly Detection

Proactive threat detection identifies attacks before they cause damage. Monitor traffic patterns, detect anomalies, and automatically trigger defensive measures.

This anomaly detection system uses statistical analysis to identify traffic deviations:

// src/monitoring/anomaly-detector.ts
// Real-time traffic anomaly detection with statistical analysis

import { EventEmitter } from 'events';

interface TrafficMetrics {
  timestamp: number;
  requestCount: number;
  errorRate: number;
  avgResponseTime: number;
  uniqueIPs: number;
  suspiciousScore: number;
}

interface AnomalyThresholds {
  requestCountMultiplier: number;
  errorRateThreshold: number;
  responseTimeMultiplier: number;
  uniqueIPRatioThreshold: number;
}

export class AnomalyDetector extends EventEmitter {
  private metricsHistory: TrafficMetrics[] = [];
  private readonly historySize: number = 60; // 60 data points
  private thresholds: AnomalyThresholds;

  constructor(thresholds: Partial<AnomalyThresholds> = {}) {
    super();
    this.thresholds = {
      requestCountMultiplier: thresholds.requestCountMultiplier || 3.0,
      errorRateThreshold: thresholds.errorRateThreshold || 0.15,
      responseTimeMultiplier: thresholds.responseTimeMultiplier || 2.5,
      uniqueIPRatioThreshold: thresholds.uniqueIPRatioThreshold || 0.1
    };
  }

  public recordMetrics(metrics: TrafficMetrics): void {
    this.metricsHistory.push(metrics);

    if (this.metricsHistory.length > this.historySize) {
      this.metricsHistory.shift();
    }

    if (this.metricsHistory.length >= 10) {
      this.detectAnomalies(metrics);
    }
  }

  private detectAnomalies(current: TrafficMetrics): void {
    const baseline = this.calculateBaseline();
    const anomalies: string[] = [];

    // Request count spike detection
    if (current.requestCount > baseline.avgRequestCount * this.thresholds.requestCountMultiplier) {
      anomalies.push('request-spike');
      this.emit('anomaly', {
        type: 'request-spike',
        severity: 'high',
        current: current.requestCount,
        baseline: baseline.avgRequestCount,
        message: `Request count ${current.requestCount} exceeds baseline ${baseline.avgRequestCount.toFixed(0)} by ${this.thresholds.requestCountMultiplier}x`
      });
    }

    // Error rate spike detection
    if (current.errorRate > this.thresholds.errorRateThreshold) {
      anomalies.push('error-spike');
      this.emit('anomaly', {
        type: 'error-spike',
        severity: 'critical',
        current: current.errorRate,
        threshold: this.thresholds.errorRateThreshold,
        message: `Error rate ${(current.errorRate * 100).toFixed(1)}% exceeds threshold ${(this.thresholds.errorRateThreshold * 100)}%`
      });
    }

    // Response time degradation
    if (current.avgResponseTime > baseline.avgResponseTime * this.thresholds.responseTimeMultiplier) {
      anomalies.push('slow-response');
      this.emit('anomaly', {
        type: 'slow-response',
        severity: 'medium',
        current: current.avgResponseTime,
        baseline: baseline.avgResponseTime,
        message: `Response time ${current.avgResponseTime.toFixed(0)}ms exceeds baseline ${baseline.avgResponseTime.toFixed(0)}ms`
      });
    }

    // Suspicious IP ratio (many requests from few IPs)
    const ipRatio = current.uniqueIPs / current.requestCount;
    if (ipRatio < this.thresholds.uniqueIPRatioThreshold) {
      anomalies.push('concentrated-traffic');
      this.emit('anomaly', {
        type: 'concentrated-traffic',
        severity: 'high',
        ratio: ipRatio,
        threshold: this.thresholds.uniqueIPRatioThreshold,
        message: `Traffic concentrated from few IPs: ratio ${ipRatio.toFixed(3)} below threshold ${this.thresholds.uniqueIPRatioThreshold}`
      });
    }

    // Suspicion score threshold
    if (current.suspiciousScore > 70) {
      anomalies.push('high-suspicion');
      this.emit('anomaly', {
        type: 'high-suspicion',
        severity: 'high',
        score: current.suspiciousScore,
        message: `Suspicion score ${current.suspiciousScore} indicates potential attack`
      });
    }

    // Combined anomaly detection (DDoS probability)
    if (anomalies.length >= 3) {
      this.emit('anomaly', {
        type: 'probable-ddos',
        severity: 'critical',
        anomalies,
        message: `Multiple anomalies detected: ${anomalies.join(', ')}. Probable DDoS attack in progress.`,
        recommendation: 'Enable emergency rate limiting and IP blocking'
      });
    }
  }

  private calculateBaseline(): {
    avgRequestCount: number;
    avgErrorRate: number;
    avgResponseTime: number;
  } {
    const recentMetrics = this.metricsHistory.slice(-30);

    const avgRequestCount = recentMetrics.reduce((sum, m) => sum + m.requestCount, 0) / recentMetrics.length;
    const avgErrorRate = recentMetrics.reduce((sum, m) => sum + m.errorRate, 0) / recentMetrics.length;
    const avgResponseTime = recentMetrics.reduce((sum, m) => sum + m.avgResponseTime, 0) / recentMetrics.length;

    return { avgRequestCount, avgErrorRate, avgResponseTime };
  }

  public getMetricsHistory(): TrafficMetrics[] {
    return [...this.metricsHistory];
  }
}

Incident Response: Automated Defense

When anomalies are detected, automated incident response activates emergency defenses. This runbook automation system executes predefined response procedures:

// src/incident-response/runbook-automation.ts
// Automated incident response for DDoS attacks

import { AnomalyDetector } from '../monitoring/anomaly-detector';
import { MultiLayerRateLimiter } from '../middleware/rate-limiter';
import axios from 'axios';

interface IncidentLog {
  timestamp: number;
  severity: string;
  type: string;
  actions: string[];
  resolved: boolean;
}

export class IncidentResponseAutomation {
  private anomalyDetector: AnomalyDetector;
  private rateLimiter: MultiLayerRateLimiter;
  private incidentLog: IncidentLog[] = [];
  private emergencyMode: boolean = false;

  constructor(
    anomalyDetector: AnomalyDetector,
    rateLimiter: MultiLayerRateLimiter
  ) {
    this.anomalyDetector = anomalyDetector;
    this.rateLimiter = rateLimiter;
    this.setupEventListeners();
  }

  private setupEventListeners(): void {
    this.anomalyDetector.on('anomaly', (event: any) => {
      this.handleAnomaly(event);
    });
  }

  private async handleAnomaly(event: any): Promise<void> {
    const incident: IncidentLog = {
      timestamp: Date.now(),
      severity: event.severity,
      type: event.type,
      actions: [],
      resolved: false
    };

    console.log(`🚨 INCIDENT DETECTED: ${event.type} (${event.severity})`);
    console.log(`   Message: ${event.message}`);

    // Execute response based on severity
    switch (event.severity) {
      case 'critical':
        await this.executeCriticalResponse(incident, event);
        break;
      case 'high':
        await this.executeHighResponse(incident, event);
        break;
      case 'medium':
        await this.executeMediumResponse(incident, event);
        break;
    }

    this.incidentLog.push(incident);
    await this.notifyTeam(incident, event);
  }

  private async executeCriticalResponse(incident: IncidentLog, event: any): Promise<void> {
    // Enable emergency mode
    this.emergencyMode = true;
    incident.actions.push('emergency-mode-enabled');

    // Aggressive rate limiting (10 req/min per IP)
    incident.actions.push('aggressive-rate-limit');

    // Block top offending IPs
    if (event.type === 'probable-ddos') {
      // This would integrate with your IP tracking system
      incident.actions.push('blocked-top-offenders');
    }

    // Scale infrastructure
    await this.triggerAutoScaling();
    incident.actions.push('triggered-auto-scaling');

    // Enable Cloudflare "I'm Under Attack" mode
    await this.enableCloudflareAttackMode();
    incident.actions.push('cloudflare-attack-mode');
  }

  private async executeHighResponse(incident: IncidentLog, event: any): Promise<void> {
    // Moderate rate limiting
    incident.actions.push('moderate-rate-limit');

    // Monitor closely
    incident.actions.push('enhanced-monitoring');
  }

  private async executeMediumResponse(incident: IncidentLog, event: any): Promise<void> {
    // Log and monitor
    incident.actions.push('logged-for-review');
  }

  private async triggerAutoScaling(): Promise<void> {
    // Example: Kubernetes API call to increase replicas
    console.log('🔧 Triggering auto-scaling...');
    // kubectl scale deployment mcp-server --replicas=20
  }

  private async enableCloudflareAttackMode(): Promise<void> {
    // Cloudflare API example
    const zoneId = process.env.CLOUDFLARE_ZONE_ID;
    const apiToken = process.env.CLOUDFLARE_API_TOKEN;

    if (!zoneId || !apiToken) return;

    try {
      await axios.patch(
        `https://api.cloudflare.com/client/v4/zones/${zoneId}/settings/security_level`,
        { value: 'under_attack' },
        { headers: { 'Authorization': `Bearer ${apiToken}` } }
      );
      console.log('🛡️  Cloudflare "Under Attack" mode enabled');
    } catch (error) {
      console.error('Failed to enable Cloudflare attack mode:', error);
    }
  }

  private async notifyTeam(incident: IncidentLog, event: any): Promise<void> {
    // Slack notification
    const webhookUrl = process.env.SLACK_WEBHOOK_URL;
    if (!webhookUrl) return;

    const message = {
      text: `🚨 *DDoS Incident Detected*`,
      attachments: [
        {
          color: event.severity === 'critical' ? 'danger' : 'warning',
          fields: [
            { title: 'Type', value: event.type, short: true },
            { title: 'Severity', value: event.severity, short: true },
            { title: 'Message', value: event.message, short: false },
            { title: 'Actions Taken', value: incident.actions.join(', '), short: false }
          ],
          ts: Math.floor(incident.timestamp / 1000)
        }
      ]
    };

    try {
      await axios.post(webhookUrl, message);
    } catch (error) {
      console.error('Failed to send Slack notification:', error);
    }
  }

  public disableEmergencyMode(): void {
    this.emergencyMode = false;
    console.log('✅ Emergency mode disabled');
  }

  public getIncidentLog(): IncidentLog[] {
    return this.incidentLog;
  }
}

Conclusion: Defense-in-Depth for ChatGPT Apps

DDoS protection for ChatGPT applications requires comprehensive defense-in-depth strategy spanning perimeter security, application-layer controls, infrastructure resilience, and automated incident response. The production-ready implementations in this guide provide battle-tested protection against volumetric attacks, application-layer exploits, and API quota exhaustion.

Start with CDN and WAF integration using Cloudflare Workers or AWS WAF to filter malicious traffic at the edge before it reaches your infrastructure. Implement multi-layer rate limiting with Redis-backed distributed state to enforce granular limits on IP addresses, authenticated users, and MCP tool calls. Deploy auto-scaling infrastructure with Kubernetes HPA to absorb traffic spikes and circuit breakers to prevent cascade failures. Enable real-time anomaly detection with statistical baseline analysis to identify attacks as they emerge. Finally, automate incident response with runbook automation that executes defensive measures when critical anomalies are detected.

DDoS attacks will only intensify as your ChatGPT app reaches OpenAI's massive user base. Implement these defenses today to protect your infrastructure, preserve your OpenAI API quota, and ensure reliable service for legitimate users.

Ready to deploy DDoS-protected ChatGPT apps without writing security code? MakeAIHQ provides enterprise-grade DDoS protection built into every app you create—Cloudflare integration, adaptive rate limiting, auto-scaling infrastructure, and 24/7 threat monitoring included. Build your first protected ChatGPT app in minutes with our no-code platform and Instant App Wizard.


Related Resources

  • ChatGPT App Security Hardening Guide - Complete security pillar guide
  • Rate Limiting & Throttling for ChatGPT Apps - Detailed rate limiting strategies
  • Cloudflare Integration for ChatGPT Apps - Cloudflare Workers deployment
  • Auto-Scaling Strategies for ChatGPT Apps - Kubernetes and serverless scaling

External References