Response:
 I'll implement comprehensive XSS prevention for the Sunaiva widget system with defense-in-depth sanitization, strict CSP headers, and injection vector mitigation.

## 1. Backend Implementation (FastAPI)

### `main.py` - Secure Widget Serving & API

```python
"""
Sunaiva Widget Security Module
Implements XSS prevention, CSP headers, and input sanitization
"""

import asyncio
import hashlib
import json
import re
from datetime import datetime, timedelta
from typing import Optional, Dict, Any, List
from enum import Enum
from uuid import uuid4

import asyncpg
import bleach
from fastapi import FastAPI, HTTPException, Request, Response, Depends, Security
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.responses import PlainTextResponse, JSONResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel, Field, validator, ValidationError
import redis.asyncio as redis
from jinja2 import Environment, FileSystemLoader, select_autoescape

# Configuration
CSP_DIRECTIVES = {
    "default-src": "'self'",
    "script-src": "'self' 'unsafe-inline' 'nonce-{nonce}'",
    "style-src": "'self' 'unsafe-inline'",
    "img-src": "'self' data: https:",
    "connect-src": "'self' https://api.sunaiva.com wss://realtime.sunaiva.com",
    "font-src": "'self'",
    "object-src": "'none'",
    "media-src": "'self'",
    "frame-src": "'none'",
    "base-uri": "'self'",
    "form-action": "'self'",
    "upgrade-insecure-requests": ""
}

ALLOWED_HTML_TAGS = [
    'p', 'br', 'strong', 'em', 'u', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
    'ul', 'ol', 'li', 'span', 'div'
]

ALLOWED_HTML_ATTRIBUTES = {
    '*': ['class', 'data-*'],
    'span': ['style'],
    'div': ['style']
}

ALLOWED_CSS_PROPERTIES = ['color', 'background-color', 'font-weight', 'text-align']

class SecurityEvent(BaseModel):
    """Model for security audit logging"""
    event_type: str
    timestamp: datetime = Field(default_factory=datetime.utcnow)
    ip_address: Optional[str] = None
    user_agent: Optional[str] = None
    widget_id: Optional[str] = None
    payload_preview: Optional[str] = None  # Truncated for safety
    severity: str = Field(..., pattern="^(low|medium|high|critical)$")

class ChatMessage(BaseModel):
    """Validated chat message input"""
    widget_id: str = Field(..., min_length=32, max_length=64)
    session_id: str = Field(..., min_length=32, max_length=64)
    message: str = Field(..., min_length=1, max_length=2000)
    message_type: str = Field(default="text", pattern="^(text|image_url)$")
    metadata: Optional[Dict[str, Any]] = Field(default_factory=dict)

    @validator('message')
    def sanitize_input(cls, v: str) -> str:
        """
        Server-side sanitization as defense in depth.
        Client-side should also sanitize, but we validate here.
        """
        if not v or not isinstance(v, str):
            raise ValueError("Message must be a non-empty string")

        # Strip null bytes
        v = v.replace('\x00', '')

        # Check for script tags and event handlers (pre-bleach validation)
        dangerous_patterns = [
            r'<script[^>]*>.*?</script>',
            r'javascript:',
            r'on\w+\s*=',
            r'data:text/html',
            r'<iframe',
            r'<object',
            r'<embed',
            r'<form',
        ]

        for pattern in dangerous_patterns:
            if re.search(pattern, v, re.IGNORECASE | re.DOTALL):
                raise ValueError(f"Potentially dangerous content detected")

        # Bleach sanitization
        clean = bleach.clean(
            v,
            tags=ALLOWED_HTML_TAGS,
            attributes=ALLOWED_HTML_ATTRIBUTES,
            strip=True
        )

        return clean

    @validator('metadata')
    def sanitize_metadata(cls, v: Dict[str, Any]) -> Dict[str, Any]:
        """Ensure metadata doesn't contain nested injection attempts"""
        if not isinstance(v, dict):
            return {}

        sanitized = {}
        for key, value in v.items():
            # Only allow primitive types
            if isinstance(value, (str, int, float, bool)):
                if isinstance(value, str):
                    # Strip HTML from metadata values
                    value = bleach.clean(value, tags=[], strip=True)
                sanitized[key] = value
        return sanitized

class WidgetConfig(BaseModel):
    """Widget configuration with security settings"""
    widget_id: str
    tenant_id: str
    csp_nonce: str = Field(default_factory=lambda: uuid4().hex[:16])
    allowed_domains: List[str] = Field(default_factory=list)
    enable_file_upload: bool = False
    max_message_length: int = 2000
    allowed_content_types: List[str] = Field(default=["text/plain", "image/jpeg", "image/png"])

app = FastAPI(title="Sunaiva Widget API", version="2.0.0")

# Security dependencies
security_bearer = HTTPBearer(auto_error=False)

# Connection pools (initialized in lifespan)
db_pool: Optional[asyncpg.Pool] = None
redis_client: Optional[redis.Redis] = None

@app.on_event("startup")
async def startup():
    global db_pool, redis_client
    db_pool = await asyncpg.create_pool(
        "postgresql://user:pass@localhost/sunaiva",
        min_size=10,
        max_size=20
    )
    redis_client = redis.Redis(
        host='localhost',
        port=6379,
        db=0,
        decode_responses=True
    )

@app.on_event("shutdown")
async def shutdown():
    if db_pool:
        await db_pool.close()
    if redis_client:
        await redis_client.close()

async def log_security_event(event: SecurityEvent):
    """Async logging of security events to PostgreSQL"""
    try:
        await db_pool.execute("""
            INSERT INTO security_audit_log
            (event_type, timestamp, ip_address, user_agent, widget_id, payload_preview, severity)
            VALUES ($1, $2, $3, $4, $5, $6, $7)
        """,
        event.event_type,
        event.timestamp,
        event.ip_address,
        event.user_agent,
        event.widget_id,
        event.payload_preview[:100] if event.payload_preview else None,
        event.severity
        )
    except Exception as e:
        # Fail silently to prevent DoS via logging failures, but alert
        print(f"CRITICAL: Failed to log security event: {e}")

async def check_rate_limit(key: str, max_requests: int = 30, window: int = 60) -> bool:
    """Redis-based rate limiting"""
    current = await redis_client.incr(key)
    if current == 1:
        await redis_client.expire(key, window)
    return current <= max_requests

def generate_csp_header(nonce: str) -> str:
    """Generate strict Content Security Policy header"""
    directives = []
    for key, value in CSP_DIRECTIVES.items():
        if "{nonce}" in value:
            value = value.format(nonce=nonce)
        if value:
            directives.append(f"{key} {value}")
        else:
            directives.append(key)
    return "; ".join(directives)

def escape_js_string(s: str) -> str:
    """Escape string for safe JavaScript injection"""
    return json.dumps(s)  # JSON encoding handles JS escaping properly

@app.get("/widget.js")
async def serve_widget(
    request: Request,
    widget_id: str,
    response: Response
) -> Response:
    """
    Serve widget.js with dynamic configuration and security headers.
    Implements XSS prevention through CSP and input validation templates.
    """
    # Rate limiting by IP to prevent enumeration attacks
    client_ip = request.client.host
    rate_key = f"widget_req:{client_ip}"
    if not await check_rate_limit(rate_key, max_requests=60):
        await log_security_event(SecurityEvent(
            event_type="rate_limit_exceeded",
            ip_address=client_ip,
            severity="medium"
        ))
        raise HTTPException(status_code=429, detail="Rate limit exceeded")

    # Validate widget_id format to prevent path traversal
    if not re.match(r'^[a-f0-9]{32,64}$', widget_id):
        await log_security_event(SecurityEvent(
            event_type="invalid_widget_id_format",
            ip_address=client_ip,
            payload_preview=widget_id,
            severity="high"
        ))
        raise HTTPException(status_code=400, detail="Invalid widget ID format")

    # Fetch widget configuration
    try:
        row = await db_pool.fetchrow(
            "SELECT tenant_id, allowed_domains, settings FROM widgets WHERE widget_id = $1 AND active = true",
            widget_id
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail="Database error")

    if not row:
        raise HTTPException(status_code=404, detail="Widget not found")

    # Generate unique nonce for this widget instance
    nonce = uuid4().hex[:16]
    config = WidgetConfig(
        widget_id=widget_id,
        tenant_id=row['tenant_id'],
        csp_nonce=nonce,
        allowed_domains=row['allowed_domains'] or []
    )

    # Render widget.js template with security context
    jinja_env = Environment(
        loader=FileSystemLoader('templates'),
        autoescape=select_autoescape(['html', 'xml', 'js']),
        enable_async=True
    )

    template = jinja_env.get_template('widget.js')

    # Generate widget code with embedded security config
    widget_code = await template.render_async(
        config=config.dict(),
        api_endpoint="https://api.sunaiva.com",
        nonce=nonce,
        escape_js=escape_js_string
    )

    # Security headers
    response.headers["Content-Type"] = "application/javascript; charset=utf-8"
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["X-Frame-Options"] = "DENY"
    response.headers["Content-Security-Policy"] = generate_csp_header(nonce)
    response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
    response.headers["Cache-Control"] = "public, max-age=3600, immutable"

    # ETag for caching
    etag = hashlib.md5(widget_code.encode()).hexdigest()
    response.headers["ETag"] = etag

    if request.headers.get("If-None-Match") == etag:
        response.status_code = 304
        return Response(content="")

    return PlainTextResponse(content=widget_code)

@app.post("/api/chat/message")
async def process_chat_message(
    message: ChatMessage,
    request: Request,
    credentials: Optional[HTTPAuthorizationCredentials] = Security(security_bearer)
) -> JSONResponse:
    """
    Process chat message with comprehensive XSS prevention.
    Implements server-side validation as defense in depth.
    """
    client_ip = request.client.host

    # Rate limiting per session
    rate_key = f"chat:{message.session_id}"
    if not await check_rate_limit(rate_key, max_requests=20, window=60):
        await log_security_event(SecurityEvent(
            event_type="chat_rate_limit",
            ip_address=client_ip,
            widget_id=message.widget_id,
            severity="low"
        ))
        raise HTTPException(status_code=429, detail="Too many messages")

    # Verify widget exists and is active
    widget_exists = await redis_client.exists(f"widget:{message.widget_id}")
    if not widget_exists:
        # Fallback to DB check
        row = await db_pool.fetchval(
            "SELECT 1 FROM widgets WHERE widget_id = $1 AND active = true",
            message.widget_id
        )
        if not row:
            await log_security_event(SecurityEvent(
                event_type="invalid_widget_access",
                ip_address=client_ip,
                widget_id=message.widget_id,
                severity="medium"
            ))
            raise HTTPException(status_code=404, detail="Widget not found")
        await redis_client.setex(f"widget:{message.widget_id}", 300, "1")

    # Additional image URL validation if message_type is image_url
    if message.message_type == "image_url":
        if not validate_image_url(message.message):
            await log_security_event(SecurityEvent(
                event_type="malicious_image_url",
                ip_address=client_ip,
                widget_id=message.widget_id,
                payload_preview=message.message,
                severity="high"
            ))
            raise HTTPException(status_code=400, detail="Invalid image URL")

    # Store sanitized message
    try:
        await db_pool.execute("""
            INSERT INTO chat_messages (widget_id, session_id, message, message_type, created_at)
            VALUES ($1, $2, $3, $4, $5)
        """, message.widget_id, message.session_id, message.message, message.message_type, datetime.utcnow())
    except Exception as e:
        raise HTTPException(status_code=500, detail="Failed to store message")

    # Process with AI (simulated)
    response_text = await process_ai_response(message.message)

    # Sanitize AI response before sending to client
    clean_response = bleach.clean(
        response_text,
        tags=ALLOWED_HTML_TAGS,
        attributes=ALLOWED_HTML_ATTRIBUTES
    )

    return JSONResponse(
        content={
            "success": True,
            "message_id": str(uuid4()),
            "response": clean_response,
            "timestamp": datetime.utcnow().isoformat()
        },
        headers={
            "X-Content-Type-Options": "nosniff",
            "Content-Security-Policy": "default-src 'none'; frame-ancestors 'none'"
        }
    )

def validate_image_url(url: str) -> bool:
    """Validate image URLs to prevent SSRF and malicious schemes"""
    allowed_schemes = ['https']
    allowed_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp']

    try:
        from urllib.parse import urlparse
        parsed = urlparse(url)

        # Check scheme
        if parsed.scheme not in allowed_schemes:
            return False

        # Check for IP-based URLs (SSRF prevention)
        if re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', parsed.hostname):
            return False

        # Check for localhost/private IPs
        hostname = parsed.hostname.lower()
        if hostname in ['localhost', '127.0.0.1', '0.0.0.0'] or hostname.startswith('internal.'):
            return False

        # Validate extension
        path = parsed.path.lower()
        if not any(path.endswith(ext) for ext in allowed_extensions):
            return False

        return True
    except Exception:
        return False

async def process_ai_response(message: str) -> str:
    """Simulated AI processing - in production this calls your AI service"""
    # This is where you'd integrate with your AI backend
    # The response should be treated as untrusted and sanitized
    return f"Received your message: {message[:50]}..."

@app.middleware("http")
async def security_headers_middleware(request: Request, call_next):
    """Add security headers to all responses"""
    response = await call_next(request)

    # Prevent MIME type sniffing
    response.headers["X-Content-Type-Options"] = "nosniff"

    # Prevent clickjacking
    response.headers["X-Frame-Options"] = "DENY"

    # XSS Protection (legacy but helpful for older browsers)
    response.headers["X-XSS-Protection"] = "1; mode=block"

    return response
```

### `templates/widget.js` - Secure Client-Side Implementation

```javascript
/**
 * Sunaiva Widget v2.0 - XSS Hardened Implementation
 *
 * Security Features:
 * - DOMPurify-based HTML sanitization
 * - CSP nonce compliance
 * - Input validation before DOM insertion
 * - SVG/Image injection prevention
 * - Event handler stripping
 */

(function(global, factory) {
    'use strict';
    if (typeof module === 'object' && typeof module.exports === 'object') {
        module.exports = factory();
    } else {
        global.SunaivaWidget = factory();
    }
})(typeof window !== 'undefined' ? window : this, function() {
    'use strict';

    // Security Configuration
    const SECURITY_CONFIG = {
        maxMessageLength: {{ config.max_message_length | default(2000) }},
        allowedTags: ['b', 'i', 'em', 'strong', 'p', 'br', 'ul', 'ol', 'li', 'span', 'div'],
        allowedAttributes: {
            '*': ['class', 'data-message-id'],
            'span': ['style'],
            'div': ['style']
        },
        allowedStyles: ['color', 'background-color', 'font-weight', 'text-align'],
        nonce: '{{ nonce }}'
    };

    /**
     * XSS Sanitization Engine
     * Implements defense-in-depth with multiple validation layers
     */
    class Sanitizer {
        constructor() {
            this.tempDiv = document.createElement('div');
            this.urlPattern = /^(https?:\/\/)[\w\-\.]+\.[a-z]{2,}(\/.*)?$/i;
        }

        /**
         * Main sanitization entry point
         * @param {string} dirty - Raw user input
         * @param {string} context - Context: 'html', 'text', 'attribute', 'url'
         * @returns {string} Sanitized output safe for given context
         */
        sanitize(dirty, context = 'html') {
            if (typeof dirty !== 'string') {
                return '';
            }

            // Trim and normalize
            dirty = dirty.trim();

            if (dirty.length > SECURITY_CONFIG.maxMessageLength) {
                console.warn('Sunaiva: Message truncated due to length');
                dirty = dirty.substring(0, SECURITY_CONFIG.maxMessageLength);
            }

            switch (context) {
                case 'html':
                    return this.sanitizeHTML(dirty);
                case 'text':
                    return this.escapeText(dirty);
                case 'attribute':
                    return this.escapeAttribute(dirty);
                case 'url':
                    return this.sanitizeURL(dirty);
                default:
                    return this.escapeText(dirty);
            }
        }

        /**
         * HTML Sanitization using browser API + whitelist
         * More lightweight than DOMPurify for controlled widget environment
         */
        sanitizeHTML(dirty) {
            // Layer 1: Remove script tags and event handlers with regex (fast path)
            let clean = this.preSanitize(dirty);

            // Layer 2: DOM-based parsing and whitelist filtering
            this.tempDiv.innerHTML = clean;
            this.sanitizeNode(this.tempDiv);

            // Layer 3: Get clean HTML
            return this.tempDiv.innerHTML;
        }

        /**
         * Pre-sanitization: Remove obvious attack vectors
         */
        preSanitize(html) {
            return html
                // Remove script tags and contents
                .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
                // Remove event handlers (onclick, onerror, etc.)
                .replace(/\s*on\w+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]*)/gi, '')
                // Remove javascript: and data: URIs
                .replace(/\s*(?:href|src|action)\s*=\s*["']?\s*javascript:[^"']*/gi, '')
                .replace(/\s*(?:href|src)\s*=\s*["']?\s*data:text\/html[^


CORS Configuration for Multi-Domain Widget Embedding

Response:
Here is a production-ready, multi-layered CORS implementation for Sunaiva that separates widget delivery (open) from API access (strict) while maintaining audit trails and high performance.

## 1. Core Configuration & Models

```python
# sunaiva/core/config/cors.py
from pydantic import Field, RedisDsn, PostgresDsn
from pydantic_settings import BaseSettings
from typing import List, Optional
import re

class CORSSettings(BaseSettings):
    """CORS configuration with environment-based overrides."""

    # Database & Cache
    database_url: PostgresDsn
    redis_url: RedisDsn

    # Widget assets (public CDN paths)
    widget_path_prefixes: List[str] = Field(default=["/widget", "/static/widget"])
    widget_cors_max_age: int = Field(default=86400, description="Cache preflight for 24h")

    # API Security
    api_path_prefixes: List[str] = Field(default=["/api/v1"])
    allowed_origins_default: List[str] = Field(default=["https://app.sunaiva.com"])

    # Regex patterns for dynamic validation (e.g., *.vercel.app preview deployments)
    allowed_origin_patterns: List[str] = Field(default=[])

    # Webhook security
    trusted_webhook_ips: List[str] = Field(default=[])
    webhook_secret_header: str = "X-Webhook-Secret"

    # Security headers
    enable_strict_transport_security: bool = True

    class Config:
        env_prefix = "SUNAIVA_CORS_"
        case_sensitive = False

    def compile_patterns(self) -> List[re.Pattern]:
        """Compile regex patterns for origin validation."""
        return [re.compile(pattern) for pattern in self.allowed_origin_patterns]

class OriginValidationResult(BaseModel):
    """Structured result for origin validation attempts."""
    allowed: bool
    origin: str
    widget_id: Optional[UUID] = None
    reason: Optional[str] = None
    cached: bool = False
```

## 2. Database Repository (Asyncpg)

```python
# sunaiva/repositories/domain_repository.py
import asyncpg
from typing import Optional, List
from uuid import UUID
import logging

logger = logging.getLogger(__name__)

class DomainRepository:
    """Manages allowed domains for widget embedding."""

    def __init__(self, pool: asyncpg.Pool):
        self.pool = pool
        self._cache_prefix = "cors:domain:"

    async def is_domain_allowed(
        self,
        domain: str,
        widget_id: Optional[UUID] = None
    ) -> bool:
        """
        Check if domain is whitelisted for API access.

        If widget_id provided, checks specific widget permissions.
        Otherwise checks global platform whitelist.
        """
        try:
            async with self.pool.acquire() as conn:
                if widget_id:
                    # Check specific widget domain binding
                    row = await conn.fetchrow(
                        """
                        SELECT 1 FROM allowed_domains
                        WHERE domain = $1
                        AND widget_id = $2
                        AND is_active = true
                        AND (expires_at IS NULL OR expires_at > NOW())
                        """,
                        domain,
                        widget_id
                    )
                else:
                    # Check global platform domains
                    row = await conn.fetchrow(
                        """
                        SELECT 1 FROM platform_domains
                        WHERE domain = $1
                        AND is_active = true
                        """,
                        domain
                    )
                return row is not None

        except asyncpg.PostgresError as e:
            logger.error(f"Database error validating domain {domain}: {e}")
            # Fail-closed: deny access on DB errors
            return False

    async def get_widget_by_domain(self, domain: str) -> Optional[UUID]:
        """Fetch widget ID associated with domain for analytics."""
        try:
            async with self.pool.acquire() as conn:
                row = await conn.fetchrow(
                    "SELECT widget_id FROM allowed_domains WHERE domain = $1 AND is_active = true",
                    domain
                )
                return row["widget_id"] if row else None
        except asyncpg.PostgresError:
            return None
```

## 3. Redis Cache Layer

```python
# sunaiva/services/cache_service.py
import redis.asyncio as redis
import json
from typing import Optional, Dict, Any
import hashlib
import logging

logger = logging.getLogger(__name__)

class CORSCache:
    """High-performance caching for origin validation to prevent DB saturation."""

    def __init__(self, redis_client: redis.Redis, ttl: int = 300):
        self.redis = redis_client
        self.ttl = ttl
        self._cache_key_prefix = "cors:origin:"

    def _get_key(self, origin: str) -> str:
        """Generate cache key with hash to handle long origins."""
        origin_hash = hashlib.sha256(origin.encode()).hexdigest()[:16]
        return f"{self._cache_key_prefix}{origin_hash}"

    async def get_validation(self, origin: str) -> Optional[Dict[str, Any]]:
        """Retrieve cached validation result."""
        try:
            key = self._get_key(origin)
            data = await self.redis.get(key)
            if data:
                return json.loads(data)
            return None
        except redis.RedisError as e:
            logger.warning(f"Redis error fetching CORS cache: {e}")
            return None

    async def set_validation(
        self,
        origin: str,
        allowed: bool,
        widget_id: Optional[str] = None,
        reason: Optional[str] = None
    ) -> None:
        """Cache validation result with TTL."""
        try:
            key = self._get_key(origin)
            value = json.dumps({
                "allowed": allowed,
                "widget_id": str(widget_id) if widget_id else None,
                "reason": reason,
                "timestamp": time.time()
            })
            await self.redis.setex(key, self.ttl, value)
        except redis.RedisError as e:
            logger.warning(f"Redis error setting CORS cache: {e}")

    async def invalidate_domain(self, domain: str) -> None:
        """Invalidate cache entries for a specific domain."""
        try:
            pattern = f"{self._cache_key_prefix}*"
            # Scan and delete matching keys (simplified for production)
            async for key in self.redis.scan_iter(match=pattern):
                await self.redis.delete(key)
        except redis.RedisError as e:
            logger.error(f"Failed to invalidate CORS cache: {e}")
```

## 4. Dynamic CORS Middleware

```python
# sunaiva/api/middleware/dynamic_cors.py
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.requests import Request
from starlette.responses import Response, JSONResponse
from starlette.types import ASGIApp
import logging
from typing import Optional
import time

logger = logging.getLogger(__name__)

class DynamicCORSMiddleware(BaseHTTPMiddleware):
    """
    Production-grade CORS middleware with path-based policy switching.

    Policies:
    - Widget assets (/widget/*): Open CORS (*), no credentials, long cache
    - API routes (/api/*): Whitelist validation, credentials enabled, strict
    - Webhooks (/webhooks/*): No CORS (server-to-server), IP validation
    """

    def __init__(
        self,
        app: ASGIApp,
        domain_repository: DomainRepository,
        cache_service: CORSCache,
        config: CORSSettings,
        metrics_client: Optional[Any] = None  # For Prometheus/DataDog
    ):
        super().__init__(app)
        self.repo = domain_repository
        self.cache = cache_service
        self.config = config
        self.metrics = metrics_client
        self.compiled_patterns = config.compile_patterns()

    def _is_widget_path(self, path: str) -> bool:
        """Check if path serves public widget assets."""
        return any(path.startswith(prefix) for prefix in self.config.widget_path_prefixes)

    def _is_api_path(self, path: str) -> bool:
        """Check if path is API endpoint requiring authentication."""
        return any(path.startswith(prefix) for prefix in self.config.api_path_prefixes)

    def _is_webhook_path(self, path: str) -> bool:
        """Check if path is webhook receiver."""
        return path.startswith("/webhooks")

    def _match_origin_pattern(self, origin: str) -> bool:
        """Validate origin against configured regex patterns."""
        return any(pattern.match(origin) for pattern in self.compiled_patterns)

    async def _validate_origin(self, origin: str) -> OriginValidationResult:
        """
        Multi-layer validation: Cache -> Regex -> Database.
        """
        start_time = time.time()

        # Layer 1: Cache check
        cached = await self.cache.get_validation(origin)
        if cached is not None:
            if self.metrics:
                await self.metrics.increment("cors.cache_hit")
            return OriginValidationResult(
                allowed=cached["allowed"],
                origin=origin,
                widget_id=cached.get("widget_id"),
                cached=True
            )

        # Layer 2: Static whitelist
        if origin in self.config.allowed_origins_default:
            await self.cache.set_validation(origin, True, reason="static_whitelist")
            return OriginValidationResult(allowed=True, origin=origin)

        # Layer 3: Regex patterns (for preview deployments)
        if self._match_origin_pattern(origin):
            await self.cache.set_validation(origin, True, reason="pattern_match")
            return OriginValidationResult(allowed=True, origin=origin)

        # Layer 4: Database lookup (expensive)
        try:
            is_allowed = await self.repo.is_domain_allowed(origin)
            widget_id = await self.repo.get_widget_by_domain(origin) if is_allowed else None

            await self.cache.set_validation(
                origin,
                is_allowed,
                widget_id=widget_id,
                reason="database_lookup"
            )

            latency = time.time() - start_time
            if self.metrics:
                await self.metrics.histogram("cors.validation_latency", latency)

            return OriginValidationResult(
                allowed=is_allowed,
                origin=origin,
                widget_id=widget_id,
                reason="database_lookup"
            )

        except Exception as e:
            logger.error(f"CORS validation failed for {origin}: {e}")
            # Fail-closed: deny on system errors
            return OriginValidationResult(
                allowed=False,
                origin=origin,
                reason="system_error"
            )

    async def dispatch(
        self,
        request: Request,
        call_next: RequestResponseEndpoint
    ) -> Response:
        origin = request.headers.get("origin")
        path = request.url.path
        method = request.method

        # Handle preflight OPTIONS
        if method == "OPTIONS":
            return await self._handle_preflight(request, origin, path)

        # Route-specific CORS policies
        if self._is_widget_path(path):
            return await self._handle_widget_request(request, call_next, origin)

        if self._is_webhook_path(path):
            return await self._handle_webhook_request(request, call_next)

        if self._is_api_path(path):
            return await self._handle_api_request(request, call_next, origin)

        # Default: pass through with minimal headers
        return await call_next(request)

    async def _handle_widget_request(
        self,
        request: Request,
        call_next: RequestResponseEndpoint,
        origin: Optional[str]
    ) -> Response:
        """
        Widget assets: Open CORS, no credentials, aggressive caching.
        """
        response = await call_next(request)

        # Allow any origin to embed the widget script
        response.headers["Access-Control-Allow-Origin"] = "*"
        response.headers["Access-Control-Allow-Methods"] = "GET, HEAD, OPTIONS"
        response.headers["Access-Control-Allow-Headers"] = "Content-Type, Accept-Encoding"
        response.headers["Access-Control-Max-Age"] = str(self.config.widget_cors_max_age)

        # Security: Never allow credentials on wildcard CORS
        # This prevents XSS from stealing session cookies via widget.js

        return response

    async def _handle_api_request(
        self,
        request: Request,
        call_next: RequestResponseEndpoint,
        origin: Optional[str]
    ) -> Response:
        """
        API endpoints: Strict whitelist validation, credentials enabled.
        """
        if not origin:
            # Non-browser clients (curl, scripts) - allow but log
            logger.debug(f"API request without Origin header: {request.url.path}")
            return await call_next(request)

        validation = await self._validate_origin(origin)

        if not validation.allowed:
            logger.warning(
                f"CORS rejected: origin={origin}, path={request.url.path}, "
                f"reason={validation.reason}, ip={request.client.host}"
            )

            if self.metrics:
                await self.metrics.increment("cors.rejected", tags={"reason": validation.reason})

            return JSONResponse(
                status_code=403,
                content={
                    "error": "origin_not_allowed",
                    "message": "This domain is not authorized to access the API",
                    "detail": "Contact support to whitelist your domain"
                },
                headers={
                    "Content-Type": "application/json",
                    "X-Error-Code": "CORS_ORIGIN_REJECTED"
                }
            )

        # Valid origin: process request and inject CORS headers
        response = await call_next(request)

        response.headers["Access-Control-Allow-Origin"] = origin
        response.headers["Access-Control-Allow-Credentials"] = "true"
        response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS, PATCH"
        response.headers["Access-Control-Allow-Headers"] = (
            "Content-Type, Authorization, X-Requested-With, X-Widget-ID"
        )
        response.headers["Access-Control-Expose-Headers"] = "X-Request-ID, X-RateLimit-Remaining"
        response.headers["Vary"] = "Origin"  # Critical for CDN caching

        # Security headers
        if self.config.enable_strict_transport_security:
            response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"

        # Audit logging for high-risk operations
        if request.method in ["POST", "PUT", "DELETE"]:
            logger.info(
                f"CORS API access: origin={origin}, widget={validation.widget_id}, "
                f"path={request.url.path}, cached={validation.cached}"
            )

        return response

    async def _handle_webhook_request(
        self,
        request: Request,


Response:
Here is a production-grade implementation of JWT Token Rotation with comprehensive security controls, optimized for Sunaiva's FastAPI architecture with PostgreSQL and Redis.

## 1. Database Schema

```sql
-- Migration: create_refresh_tokens_table.sql
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

CREATE TABLE refresh_tokens (
    jti UUID PRIMARY KEY,                    -- JWT ID from the token
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    family_id UUID NOT NULL,                 -- Token family for rotation tracking
    expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    revoked_at TIMESTAMP WITH TIME ZONE,     -- NULL = active
    replaced_by_jti UUID REFERENCES refresh_tokens(jti),
    ip_address INET,
    user_agent TEXT,

    CONSTRAINT chk_expires_after_created CHECK (expires_at > created_at)
);

-- Performance indexes
CREATE INDEX idx_refresh_tokens_user_id ON refresh_tokens(user_id) WHERE revoked_at IS NULL;
CREATE INDEX idx_refresh_tokens_family_id ON refresh_tokens(family_id);
CREATE INDEX idx_refresh_tokens_lookup ON refresh_tokens(jti, revoked_at, family_id);

-- Audit table for security events (token reuse detection)
CREATE TABLE token_security_events (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    family_id UUID NOT NULL,
    user_id UUID NOT NULL,
    event_type VARCHAR(50) NOT NULL,         -- 'reuse_detected', 'family_revoked'
    detected_jti UUID,
    source_ip INET,
    user_agent TEXT,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
```

## 2. Configuration & Schemas

```python
# src/auth/config.py
from functools import lru_cache
from pydantic_settings import BaseSettings
from typing import Literal

class AuthSettings(BaseSettings):
    """Authentication configuration loaded from environment."""

    # JWT Configuration
    secret_key: str  # HS256 key or RS256 private key
    algorithm: Literal["HS256", "RS256"] = "HS256"

    # Token Lifetimes
    access_token_expire_minutes: int = 15
    refresh_token_expire_days: int = 7

    # Redis
    redis_url: str = "redis://localhost:6379/0"

    # Database
    database_url: str = "postgresql://user:pass@localhost/sunaiva"

    # Security
    token_family_revoke_on_reuse: bool = True  # Auto-revoke family on theft detection

    class Config:
        env_prefix = "SUNAIVA_AUTH_"

@lru_cache()
def get_auth_settings() -> Auth


Response:
 I'll implement a production-grade rate limiting system for Sunaiva using FastAPI, Redis sliding windows, and tiered limits. This solution includes atomic Redis operations via Lua scripts, comprehensive error handling, and full type safety.

## 1. Core Rate Limiting Logic

```python
# src/sunaiva/core/rate_limit.py
"""
Core rate limiting implementation using Redis-backed sliding window algorithm.
Provides atomic operations via Lua scripts to prevent race conditions.
"""

import time
import uuid
from dataclasses import dataclass
from enum import Enum
from typing import Optional, Tuple

import redis.asyncio as redis
from redis.exceptions import RedisError

class RateLimitTier(Enum):
    """Subscription tiers with their respective rate limits."""
    STARTER = "starter"
    PRO = "pro"
    GROWTH = "growth"

@dataclass(frozen=True)
class RateLimitConfig:
    """Configuration for a specific rate limit tier."""
    requests_per_minute: int
    window_seconds: int = 60  # Default 1 minute window

    @property
    def requests_per_second(self) -> float:
        return self.requests_per_minute / 60

# Tier configurations
TIER_CONFIGS: dict[RateLimitTier, RateLimitConfig] = {
    RateLimitTier.STARTER: RateLimitConfig(requests_per_minute=60),
    RateLimitTier.PRO: RateLimitConfig(requests_per_minute=120),
    RateLimitTier.GROWTH: RateLimitConfig(requests_per_minute=300),
}

# Default for unauthenticated/IP-based limiting
DEFAULT_IP_CONFIG = RateLimitConfig(requests_per_minute=30, window_seconds=60)

@dataclass(frozen=True)
class RateLimitStatus:
    """Current rate limit status for a client."""
    limit: int
    remaining: int
    reset_timestamp: int
    retry_after: Optional[int] = None

    @property
    def is_allowed(self) -> bool:
        """Check if request is allowed (remaining > 0)."""
        return self.remaining > 0

class SlidingWindowRateLimiter:
    """
    Redis-backed sliding window rate limiter using atomic Lua scripts.

    Uses sorted sets (ZADD/ZREMRANGEBYSCORE) to track request timestamps
    with millisecond precision for accurate sliding windows.
    """

    def __init__(self, redis_client: redis.Redis):
        self._redis = redis_client
        self._window_script = self._redis.register_script("""
            local key = KEYS[1]
            local window_ms = tonumber(ARGV[1])
            local limit = tonumber(ARGV[2])
            local now_ms = tonumber(ARGV[3])
            local member = ARGV[4]

            -- Remove entries outside the current window
            local window_start = now_ms - window_ms
            redis.call('ZREMRANGEBYSCORE', key, 0, window_start)

            -- Count current entries in window
            local current = redis.call('ZCARD', key)

            -- Check if under limit
            if current < limit then
                -- Add current request
                redis.call('ZADD', key, now_ms, member)
                -- Set expiry to window duration
                redis.call('EXPIRE', key, math.ceil(window_ms / 1000))

                -- Return: current_count (after increment), limit, retry_after (0)
                return {current + 1, limit, 0}
            else
                -- Calculate retry after based on oldest entry
                local oldest = redis.call('ZRANGE', key, 0, 0, 'WITHSCORES')
                local retry_after_ms = (oldest[2] + window_ms) - now_ms
                return {current, limit, math.ceil(retry_after_ms / 1000)}
            end
        """)

    async def check_rate_limit(
        self,
        key: str,
        limit: int,
        window_seconds: int,
    ) -> RateLimitStatus:
        """
        Check if request is allowed and return current rate limit status.

        Args:
            key: Unique identifier (API key or IP address)
            limit: Maximum requests allowed in window
            window_seconds: Time window in seconds

        Returns:
            RateLimitStatus with current state

        Raises:
            RedisError: If Redis operation fails (should be caught by caller)
        """
        now_ms = int(time.time() * 1000)
        window_ms = window_seconds * 1000
        member = f"{now_ms}:{uuid.uuid4().hex[:8]}"  # Unique member ID

        try:
            # Execute atomic Lua script
            result = await self._window_script(
                keys=[key],
                args=[window_ms, limit, now_ms, member],
            )

            current_count, limit_val, retry_after = result

            # Calculate reset time (now + window)
            reset_timestamp = int(time.time()) + window_seconds

            return RateLimitStatus(
                limit=limit_val,
                remaining=max(0, limit_val - current_count),
                reset_timestamp=reset_timestamp,
                retry_after=retry_after if retry_after > 0 else None,
            )

        except RedisError as e:
            # Log error but fail open (allow request) to prevent total outage
            # In production, log to Sentry/Datadog
            print(f"Redis rate limit error: {e}")
            # Return permissive status on Redis failure
            return RateLimitStatus(
                limit=limit,
                remaining=1,  # Allow request
                reset_timestamp=int(time.time()) + window_seconds,
            )

    async def get_current_status(
        self,
        key: str,
        limit: int,
        window_seconds: int,
    ) -> RateLimitStatus:
        """
        Get current rate limit status without consuming a request.
        Useful for HEAD requests or status checks.
        """
        now_ms = int(time.time() * 1000)
        window_start = now_ms - (window_seconds * 1000)

        try:
            pipe = self._redis.pipeline()
            pipe.zremrangebyscore(key, 0, window_start)
            pipe.zcard(key)
            pipe.ttl(key)
            results = await pipe.execute()

            current_count = results[1]
            ttl = results[2] if results[2] > 0 else window_seconds

            return RateLimitStatus(
                limit=limit,
                remaining=max(0, limit - current_count),
                reset_timestamp=int(time.time()) + ttl,
            )
        except RedisError:
            # Fail open
            return RateLimitStatus(
                limit=limit,
                remaining=limit,
                reset_timestamp=int(time.time()) + window_seconds,
            )

class RateLimitExceededError(Exception):
    """Custom exception for rate limit violations."""

    def __init__(self, status: RateLimitStatus, message: str = "Rate limit exceeded"):
        self.status = status
        self.message = message
        super().__init__(self.message)
```

## 2. Pydantic Models & Exceptions

```python
# src/sunaiva/models/rate_limit.py
"""Pydantic models for rate limiting configuration and responses."""

from pydantic import BaseModel, Field

class RateLimitHeaders(BaseModel):
    """Standard rate limit headers for HTTP responses."""

    limit: int = Field(..., alias="X-RateLimit-Limit")
    remaining: int = Field(..., alias="X-RateLimit-Remaining")
    reset: int = Field(..., alias="X-RateLimit-Reset")
    retry_after: int | None = Field(None, alias="Retry-After")

    class Config:
        populate_by_name = True

class RateLimitInfo(BaseModel):
    """Public rate limit information for API documentation."""

    tier: str = Field(..., description="Current subscription tier")
    limit: int = Field(..., description="Requests allowed per minute")
    window_seconds: int = Field(60, description="Rate limit window duration")
```

```python
# src/sunaiva/exceptions.py
"""Custom exceptions and error handlers for Sunaiva."""

from fastapi import HTTPException, Request
from fastapi.responses import JSONResponse

class RateLimitException(HTTPException):
    """
    HTTP 429 Too Many Requests with rate limit headers.

    Includes standard rate limit headers and retry-after.
    """

    def __init__(
        self,
        limit: int,
        remaining: int,
        reset_timestamp: int,
        retry_after: int | None = None,
    ):
        headers = {
            "X-RateLimit-Limit": str(limit),
            "X-RateLimit-Remaining": str(remaining),
            "X-RateLimit-Reset": str(reset_timestamp),
        }

        if retry_after:
            headers["Retry-After"] = str(retry_after)

        super().__init__(
            status_code=429,
            detail={
                "error": "rate_limit_exceeded",
                "message": f"Rate limit of {limit} requests exceeded. "
                          f"Retry after {retry_after or '60'} seconds.",
                "limit": limit,
                "reset_timestamp": reset_timestamp,
            },
            headers=headers,
        )

async def rate_limit_exception_handler(
    request: Request,
    exc: RateLimitException,
) -> JSONResponse:
    """Global exception handler for rate limit errors."""
    return JSONResponse(
        status_code=exc.status_code,
        content=exc.detail,
        headers=dict(exc.headers) if exc.headers else {},
    )
```

## 3. FastAPI Dependencies

```python
# src/sunaiva/dependencies/rate_limit.py
"""
FastAPI dependencies for rate limiting.
Supports both API key (authenticated) and IP-based (unauthenticated) limiting.
"""

from fastapi import Depends, HTTPException, Request, Security
from fastapi.security import APIKeyHeader

from sunaiva.core.rate_limit import (
    DEFAULT_IP_CONFIG,
    TIER_CONFIGS,
    RateLimitExceededError,
    RateLimitTier,
    SlidingWindowRateLimiter,
)
from sunaiva.exceptions import RateLimitException
from sunaiva.models.rate_limit import RateLimitInfo

# Security scheme for API key extraction
api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)

def get_client_ip(request: Request) -> str:
    """
    Extract client IP from request, considering reverse proxies.

    Checks X-Forwarded-For header first, then falls back to direct IP.
    """
    # Check for forwarded IP (common with load balancers/proxies)
    forwarded = request.headers.get("X-Forwarded-For")
    if forwarded:
        # X-Forwarded-For can be a comma-separated list; take the first (client)
        ip = forwarded.split(",")[0].strip()
        return ip

    # Check alternative headers
    real_ip = request.headers.get("X-Real-IP")
    if real_ip:
        return real_ip

    # Fall back to direct connection IP
    if request.client:
        return request.client.host

    return "unknown"

class RateLimitDependency:
    """
    Dependency for tiered API key rate limiting.

    Usage:
        @app.get("/api/widgets")
        async def get_widgets(
            rate_limit: RateLimitInfo = Depends(RateLimitDependency())
        ):
            return {"widgets": []}
    """

    def __init__(self, redis_pool=None):
        self._redis_pool = redis_pool

    async def __call__(
        self,
        request: Request,
        api_key: str | None = Security(api_key_header),
    ) -> RateLimitInfo:
        """
        Check rate limit based on API key tier.

        If no API key provided, falls back to IP-based limiting with stricter limits.
        """
        if not self._redis_pool:
            # Initialize Redis connection from app state if not provided
            self._redis_pool = request.app.state.redis

        limiter = SlidingWindowRateLimiter(self._redis_pool)

        if api_key:
            return await self._check_api_key_limit(request, api_key, limiter)
        else:
            return await self._check_ip_limit(request, limiter)

    async def _check_api_key_limit(
        self,
        request: Request,
        api_key: str,
        limiter: SlidingWindowRateLimiter,
    ) -> RateLimitInfo:
        """
        Check rate limit for authenticated requests.

        In production, lookup tier from database/cache based on API key.
        For this example, we parse tier from key prefix (e.g., 'sk_starter_xxx').
        """
        # TODO: Replace with actual database lookup
        # Example: tier = await get_tier_for_api_key(api_key)
        tier = self._extract_tier_from_key(api_key)
        config = TIER_CONFIGS.get(tier, TIER_CONFIGS[RateLimitTier.STARTER])

        redis_key = f"ratelimit:api:{api_key}"

        status = await limiter.check_rate_limit(
            key=redis_key,
            limit=config.requests_per_minute,
            window_seconds=config.window_seconds,
        )

        # Store status in request state for middleware to access
        request.state.rate_limit_status = status

        if not status.is_allowed:
            raise RateLimitException(
                limit=status.limit,
                remaining=0,
                reset_timestamp=status.reset_timestamp,
                retry_after=status.retry_after,
            )

        return RateLimitInfo(
            tier=tier.value,
            limit=config.requests_per_minute,
            window_seconds=config.window_seconds,
        )

    async def _check_ip_limit(
        self,
        request: Request,
        limiter: SlidingWindowRateLimiter,
    ) -> RateLimitInfo:
        """Check rate limit for unauthenticated requests by IP."""
        ip = get_client_ip(request)
        config = DEFAULT_IP_CONFIG

        redis_key = f"ratelimit:ip:{ip}"

        status = await limiter.check_rate_limit(
            key=redis_key,
            limit=config.requests_per_minute,
            window_seconds=config.window_seconds,
        )

        request.state.rate_limit_status = status

        if not status.is_allowed:
            raise RateLimitException(
                limit=status.limit,
                remaining=0,
                reset_timestamp=status.reset_timestamp,
                retry_after=status.retry_after,
            )

        return RateLimitInfo(
            tier="anonymous",
            limit=config.requests_per_minute,
            window_seconds=config.window_seconds,
        )

    def _extract_tier_from_key(self, api_key: str) -> RateLimitTier:
        """
        Extract tier from API key format.

        Expected format: sk_{tier}_{uuid}
        Example: sk_starter_a1b2c3d4...
        """
        parts = api_key.split("_")
        if len(parts) >= 2:
            tier_str = parts[1].lower()
            try:
                return RateLimitTier(tier_str)
            except ValueError:
                pass
        return RateLimitTier.STARTER  # Default to lowest tier

class IPRateLimitDependency:
    """
    Strict IP-based rate limiting for public/unauthenticated endpoints.
    Lower limits than authenticated requests.
    """

    def __init__(self, requests_per_minute: int = 30, window_seconds: int = 60):
        self.config = DEFAULT_IP_CONFIG._replace(
            requests_per_minute=requests_per_minute,
            window_seconds=window_seconds,
        )

    async def __call__(self, request: Request) -> RateLimitInfo:
        redis_pool = request.app.state.redis
        limiter = SlidingWindowRateLimiter(redis_pool)

        ip = get_client_ip(request)
        redis_key = f"ratelimit:public:{ip}"

        status = await limiter.check_rate_limit(
            key=redis_key,
            limit=self.config.requests_per_minute,
            window_seconds=self.config.window_seconds,
        )

        request.state.rate_limit_status = status

        if not status.is_allowed:
            raise RateLimitException(
                limit=status.limit,
                remaining=0,
                reset_timestamp=status.reset_timestamp,
                retry_after=status.retry_after,
            )

        return RateLimitInfo(
            tier="public",
            limit=self.config.requests_per_minute,
            window_seconds=self.config.window_seconds,
        )
```

## 4. Middleware for Headers

```python
# src/sunaiva/middleware/rate_limit.py
"""
Middleware to inject rate limit headers into all responses.
"""

from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware

class RateLimitHeadersMiddleware(BaseHTTPMiddleware):
    """
    Middleware to add X-RateLimit-* headers to every response.

    Must be placed after authentication middleware so that rate_limit_status
    is available in request.state.
    """

    async def dispatch(self, request: Request, call_next) -> Response:
        response = await call_next(request)

        # Check if rate limit status was set by dependency
        if hasattr(request.state, "rate_limit_status"):
            status = request.state.rate_limit_status

            # Add rate limit headers to response
            response.headers["X-RateLimit-Limit"] = str(status.limit)
            response.headers["X-RateLimit-Remaining"] = str(status.remaining)
            response.headers["X-RateLimit-Reset"] = str(status.reset_timestamp)

            # Add informational tier header (optional)
            if hasattr(request.state, "rate_limit_tier"):
                response.headers["X-RateLimit-Tier"] = request.state.rate_limit_tier

        return response
```

## 5. Example Application

```python
# src/sunaiva/main.py
"""
Example FastAPI application demonstrating rate limiting.
"""

import redis.asyncio as redis
from fastapi import Depends, FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware

from sunaiva.dependencies.rate_limit import (
    IPRateLimitDependency,
    RateLimitDependency,
    get_client_ip,
)
from sunaiva.exceptions import rate_limit_exception_handler, RateLimitException
from sunaiva.middleware.rate_limit import RateLimitHeadersMiddleware
from sunaiva.models.rate_limit import RateLimitInfo

# Initialize FastAPI app
app = FastAPI(
    title="Sunaiva API",
    description="AI Voice Widgets for Small Businesses",
    version="1.0.0",
)

# Add middleware
app.add_middleware(RateLimitHeadersMiddleware)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Configure appropriately for production
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Exception handlers
app.add_exception_handler(RateLimitException, rate_limit_exception_handler)

@app.on_event("startup")
async def startup_event():
    """Initialize Redis connection on startup."""
    app.state.redis = redis.Redis(
        host="localhost",
        port=6379,
        db=0,
        decode_responses=True,
        socket_connect_timeout=5,
        socket_timeout=5,
        health_check_interval=30,
    )

@app.on_event("shutdown")
async def shutdown_event():
    """Close Redis connection on shutdown."""
    await app.state.redis.close()

# Dependencies
tiered_limit = RateLimitDependency()
public_limit = IPRateLimitDependency(requests_per_minute=20)

@app.get("/")
async def root():
    """Health check endpoint (no rate limiting)."""
    return {"status": "ok", "service": "sunaiva-api"}

@app.get("/api/widgets")
async def list_widgets(
    rate_limit: RateLimitInfo = Depends(tiered_limit),
) -> dict:
    """
    List widgets for authenticated users.
    Rate limited by API key tier (Starter: 60/min, Pro: 120/min, Growth: 300/min).
    """
    return {
        "widgets": [],
        "rate_limit": rate_limit.model_dump(),
    }

@app.post("/api/widgets")
async def create_widget(
    rate_limit: RateLimitInfo = Depends(tiered_limit),
) -> dict:
    """Create a new widget (authenticated, rate limited)."""
    return {
        "widget_id": "new-widget-123",
        "rate_limit": rate_limit.model_dump(),
    }

@app.get("/public/widget.js")
async def serve_widget_js(
    rate_limit: RateLimitInfo = Depends(public_limit),
    request: Request,
) -> dict:
    """
    Serve widget.js to customer websites.
    IP-based rate limiting with lower thresholds (20/min).
    """
    client_ip = get_client_ip(request)
    return {
        "script": "// JavaScript content here",
        "served_to": client_ip,
        "rate_limit": rate_limit.model_dump(),
    }

@app.get("/api/status")
async def check_rate_limit_status(
    request: Request,
) -> dict:
    """
    Check current rate limit status without consuming a request.
    Uses GET to avoid consuming rate limit quota.
    """
    from sunaiva.core.rate_limit import SlidingWindowRateLimiter

    limiter = SlidingWindowRateLimiter(request.app.state.redis)

    # Check both IP and potential API key limits
    ip = get_client_ip(request)
    ip_status = await limiter.get_current_status(
        key=f"ratelimit:public:{ip}",
        limit=20,
        window_seconds=60,
    )

    api_key = request.headers.get("X-API-Key")
    api_status = None

    if api_key:
        # Determine tier from key (simplified)
        tier = "starter"  # In production, lookup from DB
        limit = 60 if tier == "starter" else 120 if tier == "pro" else 300
        api_status = await limiter.get_current_status(
            key=f"ratelimit:api:{api_key}",
            limit=limit,
            window_seconds=60,
        )

    return {
        "ip_limit": {
            "limit": ip_status.limit,
            "remaining": ip_status.remaining,
            "reset": ip_status.reset_timestamp,
        },
        "api_limit": {
            "limit": api_status.limit,
            "remaining": api_status.remaining,
            "reset": api_status.reset_timestamp,
        } if api_status else None,
    }

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
```

## 6. Comprehensive Tests

```python
# tests/test_rate_limit.py
"""
Unit and integration tests for rate limiting functionality.
Includes white box tests for sliding window algorithm.
"""

import asyncio
import time
from unittest.mock import AsyncMock, MagicMock, patch

import pytest
import redis.asyncio as redis
from redis.exceptions import RedisError

from sunaiva.core.rate_limit import (
    DEFAULT_IP_CONFIG,
    RateLimitConfig,
    RateLimitStatus,
    RateLimitTier,
    SlidingWindowRateLimiter,
    TIER_CONFIGS,
)
from sunaiva.dependencies.rate_limit import get_client_ip

class TestSlidingWindowAlgorithm:
    """White box tests for sliding window counter logic."""

    @pytest.fixture
    def mock_redis(self):
        """Create a mock Redis client."""
        mock = MagicMock()
        mock.register


Response:
I'll implement comprehensive SQL injection prevention for Sunaiva's backend using defense-in-depth strategies: parameterized queries, strict input validation, and security middleware.

## 1. Database Layer with Parameterized Query Enforcement

```python
# sunaiva/database/connection.py
"""
Secure database connection management using asyncpg.
Enforces parameterized queries through abstraction layer.
"""

import asyncpg
import logging
from typing import Any, Optional, List, Dict, TypeVar, Generic
from contextlib import asynccontextmanager
from asyncpg import Connection, Pool
from pydantic import BaseModel, ValidationError

logger = logging.getLogger(__name__)
T = TypeVar('T', bound=BaseModel)

class DatabaseError(Exception):
    """Base exception for database operations."""
    pass

class SQLInjectionDetectedError(DatabaseError):
    """Raised when potential SQL injection is detected."""
    pass

class QueryBuilder:
    """
    Immutable query builder that prevents string concatenation.
    Forces use of parameterized queries.
    """

    def __init__(self, base_query: str, params: Optional[List[Any]] = None):
        """
        Initialize query builder with base SQL and parameters.

        Args:
            base_query: SQL query with $1, $2 placeholders (asyncpg style)
            params: List of parameters to substitute
        """
        self._query = base_query
        self._params = params or []
        self._validate_placeholders()

    def _validate_placeholders(self) -> None:
        """Ensure query uses proper placeholder syntax."""
        # Prevent string formatting operators
        if '%' in self._query and '%%' not in self._query:
            raise SQLInjectionDetectedError(
                "Raw % formatting detected. Use $1, $2 placeholders only."
            )

        # Prevent f-string or .format() patterns
        if '{' in self._query or '}' in self._query:
            raise SQLInjectionDetectedError(
                "Curly braces detected. Use $1, $2 placeholders only."
            )

        # Verify parameter count matches placeholders
        placeholder_count = self._query.count('$')
        if placeholder_count != len(self._params):
            raise DatabaseError(
                f"Parameter mismatch: {placeholder_count} placeholders, "
                f"{len(self._params)} values"
            )

    @property
    def query(self) -> str:
        """Read-only access to query string."""
        return self._query

    @property
    def params(self) tuple[Any, ...]:
        """Read-only access to parameters tuple."""
        return tuple(self._params)

    def where(self, condition: str, *values: Any) -> 'QueryBuilder':
        """
        Safely add WHERE clause with new placeholders.

        Args:
            condition: Condition using next available placeholder numbers
            values: Values to parameterize
        """
        # Calculate next placeholder number
        current_count = len(self._params)
        new_params = list(self._params) + list(values)

        # Validate condition doesn't contain raw values
        if any(char in condition for char in ["'", '"', ';', '--', '/*']):
            raise SQLInjectionDetectedError(
                f"Potential SQL injection in condition: {condition}"
            )

        new_query = f"{self._query} WHERE {condition}"
        return QueryBuilder(new_query, new_params)

class SecureDatabase:
    """
    Database wrapper enforcing secure query patterns.
    All queries must use QueryBuilder or explicit parameterization.
    """

    def __init__(self, dsn: str):
        self.dsn = dsn
        self._pool: Optional[Pool] = None

    async def connect(self) -> None:
        """Initialize connection pool with security settings."""
        self._pool = await asyncpg.create_pool(
            self.dsn,
            min_size=5,
            max_size=20,
            command_timeout=60,
            server_settings={
                'jit': 'off',  # Prevent JIT compilation exploits
                'application_name': 'sunaiva_api'
            }
        )
        logger.info("Secure database pool initialized")

    async def disconnect(self) -> None:
        """Close connection pool."""
        if self._pool:
            await self._pool.close()

    @asynccontextmanager
    async def acquire(self):
        """Context manager for connection acquisition."""
        if not self._pool:
            raise DatabaseError("Database not connected")

        async with self._pool.acquire() as conn:
            # Set read-only mode for specific roles if needed
            yield conn

    async def fetch(
        self,
        query_builder: QueryBuilder,
        conn: Optional[Connection] = None
    ) -> List[asyncpg.Record]:
        """
        Execute SELECT query with mandatory parameterization.

        ⚠ NEVER use: await db.fetch(f"SELECT * FROM users WHERE id = {user_id}")
        ✅ ALWAYS use: await db.fetch(QueryBuilder("SELECT * FROM users WHERE id = $1", [user_id]))
        """
        if conn:
            return await conn.fetch(query_builder.query, *query_builder.params)

        async with self.acquire() as conn:
            return await conn.fetch(query_builder.query, *query_builder.params)

    async def fetchrow(
        self,
        query_builder: QueryBuilder,
        conn: Optional[Connection] = None
    ) -> Optional[asyncpg.Record]:
        """Execute single-row SELECT."""
        if conn:
            return await conn.fetchrow(query_builder.query, *query_builder.params)

        async with self.acquire() as conn:
            return await conn.fetchrow(query_builder.query, *query_builder.params)

    async def execute(
        self,
        query_builder: QueryBuilder,
        conn: Optional[Connection] = None
    ) -> str:
        """Execute INSERT/UPDATE/DELETE."""
        if conn:
            return await conn.execute(query_builder.query, *query_builder.params)

        async with self.acquire() as conn:
            return await conn.execute(query_builder.query, *query_builder.params)

    async def fetchval(
        self,
        query_builder: QueryBuilder,
        conn: Optional[Connection] = None
    ) -> Any:
        """Execute query returning single value."""
        if conn:
            return await conn.fetchval(query_builder.query, *query_builder.params)

        async with self.acquire() as conn:
            return await conn.fetchval(query_builder.query, *query_builder.params)

# Global instance
db = SecureDatabase(dsn="postgresql://...")
```

## 2. Repository Pattern with Input Validation

```python
# sunaiva/repositories/base.py
from abc import ABC, abstractmethod
from typing import TypeVar, Generic, List, Optional, Dict, Any
from uuid import UUID
from pydantic import BaseModel, Field, validator
import re

from sunaiva.database.connection import SecureDatabase, QueryBuilder, db
from sunaiva.models.base import SunaivaBaseModel

T = TypeVar('T', bound=SunaivaBaseModel)

class SafeString(BaseModel):
    """
    Pydantic model for SQL-safe strings.
    Prevents SQL metacharacters at validation layer.
    """
    value: str = Field(..., min_length=1, max_length=255)

    @validator('value')
    def check_sql_metacharacters(cls, v: str) -> str:
        """
        Reject strings containing SQL metacharacters.
        Defense in depth: database layer also parameterizes.
        """
        dangerous_patterns = [
            r'(\%27)|(\')|(\-\-)',  # Single quote, comment
            r'(\%23)|(#)',          # Hash comment
            r'(\%22)|(")',          # Double quote
            r'(\%3B)|(;)',          # Semicolon
            r'(\%2F\%2A)|(/\*)',    # Comment start
            r'(\%2A\%2F)|(\*/)',    # Comment end
            r'union\s+select',       # UNION injection
            r'exec\s*\(',           # EXEC injection
            r'eval\s*\(',           # Eval injection
        ]

        for pattern in dangerous_patterns:
            if re.search(pattern, v, re.IGNORECASE):
                raise ValueError(f"Potentially dangerous characters detected")

        return v.strip()

class BaseRepository(Generic[T], ABC):
    """
    Base repository enforcing parameterized queries.
    All sub-classes must implement table_name and model_class.
    """

    def __init__(self, database: SecureDatabase = db):
        self.db = database
        self._table: str = self._get_table_name()
        self._validate_table_name()

    @abstractmethod
    def _get_table_name(self) -> str:
        """Return table name. Must be hardcoded, not dynamic."""
        pass

    @property
    @abstractmethod
    def model_class(self) -> type[T]:
        """Return Pydantic model class for this entity."""
        pass

    def _validate_table_name(self) -> None:
        """
        Prevent table name injection.
        Table names must be alphanumeric with underscores only.
        """
        if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', self._table):
            raise ValueError(f"Invalid table name: {self._table}")

    async def get_by_id(self, entity_id: UUID) -> Optional[T]:
        """
        Retrieve entity by ID using parameterized query.

        Args:
            entity_id: Validated UUID (not string to prevent injection)
        """
        # UUID type ensures validation before query construction
        query = QueryBuilder(
            f"SELECT * FROM {self._table} WHERE id = $1 AND deleted_at IS NULL",
            [entity_id]  # asyncpg handles UUID serialization safely
        )

        row = await self.db.fetchrow(query)
        return self.model_class(**row) if row else None

    async def search_by_field(
        self,
        field_name: str,
        value: Any,
        limit: int = 100
    ) -> List[T]:
        """
        Search by field with strict allowlist validation.

        ⚠ NEVER allow dynamic field names without validation
        """
        # Strict allowlist of searchable fields
        allowed_fields = getattr(self.model_class, '__searchable_fields__', [])

        if field_name not in allowed_fields:
            raise ValueError(
                f"Field '{field_name}' not in searchable allowlist: {allowed_fields}"
            )

        # Validate field name format (alphanumeric + underscore only)
        if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', field_name):
            raise ValueError(f"Invalid field name format: {field_name}")

        # Limit validation to prevent DoS
        safe_limit = min(max(limit, 1), 1000)

        query = QueryBuilder(
            f"""
            SELECT * FROM {self._table}
            WHERE {field_name} = $1
            AND deleted_at IS NULL
            LIMIT $2
            """,
            [value, safe_limit]
        )

        rows = await self.db.fetch(query)
        return [self.model_class(**row) for row in rows]

    async def safe_search(
        self,
        search_term: SafeString,
        search_columns: List[str]
    ) -> List[T]:
        """
        Full-text search with parameterized ILIKE.

        Args:
            search_term: Validated safe string
            search_columns: List of columns to search (validated)
        """
        # Validate all columns exist in model
        allowed = getattr(self.model_class, '__searchable_fields__', [])
        for col in search_columns:
            if col not in allowed:
                raise ValueError(f"Column {col} not searchable")

        # Build safe OR conditions with parameterized values
        conditions = []
        params = [f"%{search_term.value}%"]  # Wildcards added safely

        for i, col in enumerate(search_columns, start=2):
            conditions.append(f"{col} ILIKE $1")

        where_clause = " OR ".join(conditions)

        query = QueryBuilder(
            f"""
            SELECT * FROM {self._table}
            WHERE ({where_clause})
            AND deleted_at IS NULL
            ORDER BY created_at DESC
            LIMIT $2
            """,
            params + [100]  # Additional parameter for limit
        )

        rows = await self.db.fetch(query)
        return [self.model_class(**row) for row in rows]
```

## 3. Concrete Repository Implementation

```python
# sunaiva/repositories/widget.py
from datetime import datetime
from typing import List, Optional
from uuid import UUID, uuid4
from pydantic import Field, validator

from sunaiva.repositories.base import BaseRepository, SafeString
from sunaiva.database.connection import QueryBuilder
from sunaiva.models.base import SunaivaBaseModel

class WidgetModel(SunaivaBaseModel):
    """Pydantic model for Voice Widgets with strict validation."""

    __searchable_fields__ = ['name', 'business_name', 'domain']

    id: UUID = Field(default_factory=uuid4)
    account_id: UUID
    name: str = Field(..., min_length=1, max_length=100)
    business_name: str = Field(..., min_length=1, max_length=200)
    domain: str = Field(..., regex=r'^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$')
    config: dict = Field(default_factory=dict)
    is_active: bool = True
    created_at: Optional[datetime] = None
    updated_at: Optional[datetime] = None

    @validator('name', 'business_name')
    def prevent_sql_injection(cls, v: str) -> str:
        """Additional validation layer for text fields."""
        # Block common SQL injection patterns
        forbidden = ['--', '/*', '*/', ';', 'DROP', 'UNION', 'SELECT', 'INSERT']
        upper_v = v.upper()
        for keyword in forbidden:
            if keyword in upper_v:
                raise ValueError(f"Invalid characters in field")
        return v

class WidgetRepository(BaseRepository[WidgetModel]):
    """Secure repository for widget operations."""

    def _get_table_name(self) -> str:
        return "widgets"

    @property
    def model_class(self) -> type[WidgetModel]:
        return WidgetModel

    async def get_by_domain(self, domain: str) -> Optional[WidgetModel]:
        """
        Retrieve widget by domain with strict domain validation.

        Args:
            domain: Must match domain regex pattern
        """
        # Validation happens in Pydantic model, but we double-check here
        if not isinstance(domain, str) or len(domain) > 253:
            raise ValueError("Invalid domain format")

        query = QueryBuilder(
            """
            SELECT * FROM widgets
            WHERE domain = $1
            AND is_active = true
            AND deleted_at IS NULL
            """,
            [domain]  # Parameterized - safe from injection
        )

        row = await self.db.fetchrow(query)
        return self.model_class(**row) if row else None

    async def update_config(self, widget_id: UUID, config: dict) -> WidgetModel:
        """
        Update widget configuration safely.

        Uses JSONB operators which are inherently safe when parameterized.
        """
        import json

        # Serialize config to JSON string to ensure type safety
        config_json = json.dumps(config)

        query = QueryBuilder(
            """
            UPDATE widgets
            SET config = $1::jsonb,
                updated_at = NOW()
            WHERE id = $2
            AND deleted_at IS NULL
            RETURNING *
            """,
            [config_json, widget_id]
        )

        row = await self.db.fetchrow(query)
        if not row:
            raise ValueError(f"Widget {widget_id} not found")

        return self.model_class(**row)

    async def complex_search(
        self,
        account_id: Optional[UUID] = None,
        is_active: Optional[bool] = None,
        name_contains: Optional[str] = None,
        created_after: Optional[datetime] = None
    ) -> List[WidgetModel]:
        """
        Dynamic query builder with guaranteed parameterization.

        Demonstrates safe dynamic query construction.
        """
        conditions = ["deleted_at IS NULL"]
        params: List[Any] = []
        param_index = 1

        # Build conditions dynamically but safely
        if account_id is not None:
            conditions.append(f"account_id = ${param_index}")
            params.append(account_id)
            param_index += 1

        if is_active is not None:
            conditions.append(f"is_active = ${param_index}")
            params.append(is_active)
            param_index += 1

        if name_contains is not None:
            # Validate and sanitize search term
            safe_term = SafeString(value=name_contains)
            conditions.append(f"name ILIKE ${param_index}")
            params.append(f"%{safe_term.value}%")
            param_index += 1

        if created_after is not None:
            conditions.append(f"created_at > ${param_index}")
            params.append(created_after)
            param_index += 1

        where_clause = " AND ".join(conditions)

        query = QueryBuilder(
            f"""
            SELECT * FROM widgets
            WHERE {where_column}
            ORDER BY created_at DESC
            LIMIT ${param_index}
            """,
            params + [100]  # Add limit as final parameter
        )

        rows = await self.db.fetch(query)
        return [self.model_class(**row) for row in rows]
```

## 4. API Layer with Security Middleware

```python
# sunaiva/api/middleware/security.py
"""
Security middleware for SQL injection detection and prevention.
"""

import re
import logging
from fastapi import Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse

logger = logging.getLogger(__name__)

class SQLInjectionMiddleware(BaseHTTPMiddleware):
    """
    Middleware to detect and block SQL injection attempts.
    Defense in depth: Database layer is primary defense, this is secondary.
    """

    # Patterns to detect in query params, headers, and body
    SQLI_PATTERNS = [
        r'(\%27)|(\')|(\-\-)',           # Single quote, comment
        r'(\%3B)|(;)',                   # Semicolon
        r'((\%3D)|(=))[^\n]*((\%27)|(\')|(\-\-)|(\%3B)|(;))',  # Equals followed by quote
        r'\w*((\%27)|(\'))((\%6F)|o|(\%4F))((\%72)|r|(\%52))',  # 'or'
        r'((\%27)|(\'))union',           # 'union
        r'exec(\s|\+)+(s|x)p\w+',        # EXEC xp_
        r'UNION\s+SELECT',               # UNION SELECT
        r'INSERT\s+INTO',                # INSERT INTO
        r'DELETE\s+FROM',                # DELETE FROM
        r'DROP\s+TABLE',                 # DROP TABLE
    ]

    async def dispatch(self, request: Request, call_next):
        """Inspect request for SQL injection patterns."""
        try:
            # Check query parameters
            for key, values in request.query_params.multi_items():
                for value in values:
                    if self._detect_sqli(value):
                        logger.warning(
                            f"SQL Injection attempt detected in query param: {key}",
                            extra={
                                "client_ip": request.client.host,
                                "path": request.url.path,
                                "pattern": "query_param"
                            }
                        )
                        raise HTTPException(
                            status_code=400,
                            detail="Invalid input detected"
                        )

            # Check path parameters (if any suspicious patterns)
            for key, value in request.path_params.items():
                if isinstance(value, str) and self._detect_sqli(value):
                    logger.warning(
                        f"SQL Injection attempt in path param: {key}",
                        extra={"client_ip": request.client.host}
                    )
                    raise HTTPException(status_code=400, detail="Invalid path parameter")

            response = await call_next(request)
            return response

        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"Security middleware error: {e}")
            return JSONResponse(
                status_code=500,
                content={"detail": "Internal server error"}
            )

    def _detect_sqli(self, value: str) -> bool:
        """
        Detect SQL injection patterns in string value.
        Returns True if suspicious patterns found.
        """
        if not isinstance(value, str):
            return False

        # Check against all patterns
        for pattern in self.SQLI_PATTERNS:
            if re.search(pattern, value, re.IGNORECASE):
                return True

        return False

# sunaiva/api/routes/widgets.py
from typing import List, Optional
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query, Path
from pydantic import BaseModel, Field, validator

from sunaiva.repositories.widget import WidgetRepository, WidgetModel
from sunaiva.repositories.base import SafeString
from sunaiva.api.dependencies import get_current_user, require_account_access

router = APIRouter(prefix="/widgets", tags=["widgets"])

class WidgetCreateRequest(BaseModel):
    """Validated request model for widget creation."""
    name: str = Field(..., min_length=1, max_length=100)
    business_name: str = Field(..., min_length=1, max_length=200)
    domain: str = Field(..., regex=r'^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$')

    @validator('name', 'business_name')
    def sanitize_input(cls, v: str) -> str:
        """Remove potentially dangerous characters."""
        # Additional layer: strip HTML and SQL-like patterns
        dangerous = ['<script>', 'javascript:', 'onerror=', 'onload=']
        lower_v = v.lower()
        for d in dangerous:
            if d in lower_v:
                raise ValueError("Invalid content detected")
        return v.strip()

class WidgetSearchRequest(BaseModel):
    """Safe search request with validated fields."""
    search_term: Optional[str] = Field(None, max_length=100)
    is_active: Optional[bool] = None

    @validator('search_term')
    def validate_search_term(cls, v: Optional[str]) -> Optional[str]:
        if v is None:
            return None

        # Use SafeString validation
        try:
            safe = SafeString(value=v)
            return safe.value
        except ValueError as e:
            raise ValueError(f"Invalid search term: {e}")

@router.get("/{widget_id}", response_model=WidgetModel)
async def get_widget(
    widget_id: UUID = Path(..., description="Widget UUID"),
    repo: WidgetRepository = Depends(),
    current_user: dict = Depends(get_current_user)
):
    """
    Retrieve widget by ID.

    UUID type in path parameter prevents string-based injection.
    """
    widget = await repo.get_by_id(widget_id)
    if not widget: