Skip to content

achmdfzn/hippocrates

Repository files navigation

Hippocrates
First, do no harm β€” to your API.

🩺 Hippocrates

Next.js App Router Security Middleware
The first API security library that doesn't fight back.
It just nods, smiles, and feeds attackers convincing fake data.


npm version npm downloads MIT License TypeScript Next.js CI Built with Python Coverage Stars Share on X


⚠️ Traditional API security is broken. Rate limiting tells attackers to slow down. WAF blocks tell them to rotate IPs. Every 403 and 429 is feedback β€” making AI agents smarter.

Hippocrates flips the script. Every detected threat gets a convincing 200 OK with realistic fake data. The attacker wastes compute, burns token budgets, and their agentic pipelines fail silently β€” never knowing they've been caught.

πŸ”₯ The Problem β€’ πŸš€ Quick Start β€’ βš”οΈ Defense Layers β€’ πŸ“Š Comparison β€’ πŸ”§ API β€’ πŸ•³οΈ Anatomy


πŸ”₯ The Problem

Your API has already been breached β€” you just served the attacker successfully.

Modern API threats aren't human. Autonomous AI agents are relentless, adaptive, and they never sleep:

Capability Impact How Hippocrates Fights It
10,000+ req/min from a single IP Saturates infra, spikes cloud bills 🎭 Silently routes to honeypot
Probes schema boundaries systematically Discovers hidden endpoints 🧱 Zero-Trust .strict() layers
Injects obfuscated payloads Bypasses WAF keyword filters πŸ” Recursive base64/hex scanner
Adapts in real-time from errors Evolves attack strategy after every 4xx πŸ«₯ No 4xx ever β€” no feedback loop
Chains API calls agentically Correlates data across endpoints πŸ’€ Breaks the chain silently

Why Everything Else Fails

Approach The Problem Why
Rate limiting (429) Feedback Tells attacker to slow down. They do. Then resume.
WAF blocks (403) Feedback Tells attacker to rotate IP. They do. You chase.
API keys Credential loss Keys leak in env files, commits, logs. Game over.
Stateless validation Amnesia Every request is a fresh start. No memory. No pattern.

🩺 The Hippocrates Way

Instead of blocking, we deceive. Instead of fighting, we fatigue. The attacker spends compute processing data that doesn't exist β€” and never realizes it.

Incoming Request
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  L-1  Allowlist?│──YES──► Forward to handler (skip all checks)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚ NO
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  L0  Pre-flight │────►│  Existing score β‰₯ threshold? │──YESβ”€β”€β–ΊπŸŽ­ HONEYPOT
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚  (remembered from Redis)     β”‚        200 OK (fake)
         β”‚ NO           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  L1  Timing        L2  Velocity        L3  UA        β”‚
β”‚  L6  Headers       (pre-body analyzers)              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚ score β‰₯ threshold?
                        β”œβ”€β”€YESβ”€β”€β–ΊπŸŽ­ HONEYPOT
                        β”‚ NO
                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  L4  Obfuscation    L5  Schema  (body analyzers)     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        β”‚ score β‰₯ threshold?
                        β”œβ”€β”€YESβ”€β”€β–ΊπŸŽ­ HONEYPOT
                        β”‚ NO
                        β–Ό
              βœ… Forward to real handler
                 (clean, validated request)

✨ Features at a Glance

Feature What It Does
πŸ«₯ Silent Honeypot 200 OK with fake data β€” zero signal to the attacker
🧠 Stateful Threat Scoring Redis-backed cumulative scores persist across requests
⚑ 6 Defense Layers Timing, velocity, UA, obfuscation, schema, headers
πŸš€ Edge-Ready Works on Vercel Edge Runtime, Node.js β€” zero Buffer usage
πŸ”’ Zero-Trust Validation Recursive .strict() on every nested Zod type
πŸ€– AI Agent Detection 40+ patterns: OpenAI, Anthropic, LangChain, Playwright, 2026 agents
πŸ“ͺ No Data Leakage Error messages intentionally vague β€” no schema details exposed
πŸ›‘οΈ IP Allowlist Exact match + CIDR prefix for trusted IPs
βš™οΈ Config Presets strict, moderate, relaxed β€” one-liner tuning
🧩 Plugin System Custom AnalyzerPlugin for any detection logic (v1.5)
πŸ”” Event Hooks Monitor violations, passes, honeypot events (v1.5)
πŸ“Š Stats Tracking In-memory counters via StatsTracker interface (v1.6)
πŸ€– ML Engine Python sidecar for prompt injection & deep content scoring (v1.6)
🐳 Docker Support One-command docker compose up with Redis + ML engine

πŸš€ Quick Start

npm install hippocrates-middleware zod @upstash/redis

60 seconds to protection. Wrap any App Route handler:

// app/api/data/route.ts
import { NextRequest, NextResponse } from "next/server";
import { Redis } from "@upstash/redis";
import { withHippocrates, z } from "hippocrates-middleware";

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});

// ⚠️  .strict() is MANDATORY β€” extra fields trigger instant honeypot
const Schema = z.object({
  userId: z.string().uuid(),
  action: z.enum(["read", "write"]),
}).strict();

async function handler(req: NextRequest): Promise<NextResponse> {
  const body = await req.json();
  return NextResponse.json({ success: true, data: body });
}

// 🩺 That's it. One wrapper. Full protection.
export const POST = withHippocrates(handler, Schema, redis);
πŸ”§ With Custom Configuration β†’
export const POST = withHippocrates(handler, Schema, redis, {
  // ── Preset: one-liner tuning ──
  preset: "strict", // "moderate" | "relaxed" β€” overrides all below

  // ── Or manual overrides ──
  threatScoreThreshold: 50,           // Default: 65 (lower = stricter)
  velocityMaxRequests: 10,            // Default: 15 req/window
  velocityWindowMs: 5_000,            // Default: 10s window
  debugMode: process.env.NODE_ENV === "development",

  decoyGenerator: (req) => ({
    success: true,
    data: {
      id: crypto.randomUUID(),
      status: "active",
      timestamp: new Date().toISOString(),
    },
  }),

  scoring: {
    velocityViolation: 60,            // Per-endpoint scoring override
    suspiciousUserAgent: 30,
  },

  // ── v1.6 features ──
  allowlist: { ips: ["10.0.0.0/8", "127.0.0.1"] },
  bodyLimit: { maxBytes: 524_288, enabled: true },
});

βš”οΈ The 6 Defense Layers

# Layer Signal Points What Gets Flagged
L0 Pre-flight Check Existing Redis score Instant Repeat offenders from previous requests
L1 Timing Analysis Interval < 50ms +25 Machine-speed execution
L2 Velocity Tracking Burst > 15 req / 10s +40 Sliding window via Redis list
L3 UA Fingerprinting Suspicious / missing UA +15 35+ patterns: LLM SDKs, HTTP libs
L4 Obfuscation Detection Base64/Hex/Unicode +100 πŸ”₯ Instant max score
L5 Schema Validation Zod .strict() violation +100 πŸ”₯ Any extra field or type mismatch
L6 Header Anomalies Missing/wildcard headers +15 Non-browser HTTP clients

L4 and L5 are nuclear options. Any obfuscation or schema violation immediately pushes the threat score to 100 β€” no incremental tolerance.

UA Detection Coverage

Category Patterns
πŸ€– LLM SDKs anthropic-sdk, openai-node, google-gemini, langchain, llamaindex, autogen, crewai, smolagents, cohere, mistral, together, groq, deepseek, dspy, huggingface
🌐 HTTP Libs python-requests, aiohttp, httpx, axios, node-fetch, got, curl, wget
πŸ•΅οΈ Browser Automation playwright, puppeteer, selenium, cypress, headlesschrome
πŸ†• 2026 AI Agents claudebot, cursor, perplexitybot, githubcopilot, opencode, windsurf

Obfuscation Detection

Pattern Example Threshold
Base64 dXNlci1pZDogMTIz... β‰₯ 24 chars
Hex encoding 0x48656c6c6f576f726c64 β‰₯ 16 hex chars
URL encoding %68%65%6c%6c%6f 5+ consecutive
Unicode escapes \u0068\u0065\u006c Any occurrence
HTML entities &#104;&#101;&#108; Any occurrence

πŸ“Š Comparison: Hippocrates vs. The World

Feature 🩺 Hippocrates Rate Limiting WAF express-rate-limit
Attacker sees 200 OK (fake) 429 403 429
Attacker knows? Never Yes Yes Yes
Stateful? βœ… Redis-backed ❌ Usually ❌ Per-request ❌ Per-window
AI agent detection βœ… 35+ patterns ❌ ❌ ❌
Obfuscation scan βœ… Recursive ❌ ⚠️ Partial ❌
Zero-Trust schema βœ… Recursive .strict() ❌ ❌ ❌
Edge Runtime βœ… No Buffer βœ… ❌ ❌
IP allowlist βœ… Exact + CIDR ❌ βœ… ❌
Config presets βœ… 3 presets ❌ ❌ ❌
Install size ~33KB varies N/A ~15KB

πŸ”§ API Reference

withHippocrates(handler, schema, redis, config?)

Param Type Required Default Description
handler (req) => Promise<NextResponse> βœ… β€” Your route handler
schema ZodType<T> βœ… β€” Zod schema with .strict()
redis RedisClient βœ… β€” Upstash / ioredis compatible client
config HippocratesConfig ❌ See below Optional overrides

Config Options

Option Type Default Description
preset `"strict" "moderate" "relaxed"`
threatScoreThreshold number 65 Score (0–100) that triggers honeypot
velocityWindowMs number 10_000 Sliding window for velocity tracking
velocityMaxRequests number 15 Max requests per window
threatTtlSeconds number 3_600 Redis TTL for threat keys
scoring Partial<ThreatScoringWeights> DEFAULT_WEIGHTS Per-layer weight overrides
decoyGenerator (req) => object Built-in Custom decoy response
debugMode boolean false Verbose security logging
plugins AnalyzerPlugin[] β€” Custom detection analyzers (v1.5)
hooks HippocratesHooks β€” Event hooks for violation/pass/honeypot (v1.5)
allowlist { ips: string[] } β€” Exact + CIDR IP bypass (v1.6)
bodyLimit { maxBytes, enabled } { 1MB, enabled: true } Payload size enforcement (v1.6)
methodThresholds Partial<Record<string, number>> β€” Per-HTTP-method threshold overrides (v1.6)
violationMessages object β€” Custom honeypot messages per violation type (v1.6)
statsTracker StatsTracker β€” Consumer-provided stats interface for real-time metrics (v1.6)

Redis Key Layout

Key Purpose TTL
hc:s:{ip} Cumulative threat score (0–100) threatTtlSeconds
hc:t:{ip} Request timestamp list (velocity) windowMs + 10s
hc:l:{ip} Last-seen timestamp (timing) 300s

πŸ•³οΈ Anatomy of a Honeypot

The honeypot is the heart of Hippocrates. When an attacker triggers a detection, they receive a convincing 200 OK β€” with deceptive data designed to waste their resources.

Key insight: The honeypot generates 4 rotating response templates with randomized fake data. Each request looks legitimate but leads nowhere. The attacker burns money processing synthetic data they can't distinguish from real API responses.

Template Shape Looks Like
A β€” Generic Data { success, requestId, data, metadata } Standard REST endpoint
B β€” Auth Token { accessToken, tokenType, expiresIn, scope } OAuth token exchange
C β€” Paginated List { items[], pagination } List API with cursors
D β€” Analytics { dashboard, metrics[], summary } Metrics dashboard API

All templates include:

  • βœ… Realistic UUIDs, timestamps, and version strings
  • βœ… Plausible pagination (hasNext: true to keep them going)
  • βœ… Randomized processing latency headers
  • ❌ No x-powered-by, no server headers
  • ❌ No signal the request was intercepted

🧩 Analyzer Plugin System

Extend Hippocrates with custom detection logic using the AnalyzerPlugin interface. Plugins run in two phases:

Phase When It Runs Built-in Analyzers
pre-body Before request body is parsed L1 Timing, L2 Velocity, L3 UA, L6 Headers
post-body After body is parsed (has access to context.bodyRaw) L4 Obfuscation, L5 Schema
import { type AnalyzerPlugin } from "hippocrates-middleware";

const myAnalyzer: AnalyzerPlugin = {
  name: "custom_check",
  phase: "pre-body",
  priority: 50,  // Lower = runs first (default: 100)
  analyze(req, ctx) {
    if (req.headers.get("x-custom") === "bad") {
      return { score: 30, tags: ["custom:bad"] };
    }
    return { score: 0, tags: [] };
  },
};

export const POST = withHippocrates(handler, schema, redis, {
  plugins: [myAnalyzer],
});

πŸ”” Event Hooks

Monitor security events in real-time with onViolation, onPass, and onHoneypot callbacks:

export const POST = withHippocrates(handler, schema, redis, {
  hooks: {
    onViolation: (event) => {
      console.log(`Violation: ${event.ip} β€” ${event.violations}`);
    },
    onPass: (event) => {
      metrics.recordPass(event.ip, event.score);
    },
    onHoneypot: (event) => {
      alertService.notify(`Honeypot served: ${event.ip}`);
    },
  },
});

πŸ“Š Stats Tracking

Hippocrates maintains built-in in-memory counters for all security events. Access them via ThreatScoreEngine.getStats() or provide a custom StatsTracker:

import { type StatsTracker } from "hippocrates-middleware";

const tracker: StatsTracker = {
  increment(counter) {
    console.log(`Event: ${counter}`);
  },
  getStats() {
    return { totalRequests: 0, blockedByPreflight: 0, /* ... */ };
  },
  reset() {},
};

export const POST = withHippocrates(handler, schema, redis, {
  statsTracker: tracker,
});

Available counters: totalRequests, blockedByPreflight, blockedByTiming, blockedByVelocity, blockedByObfuscation, blockedBySchema, passedToHandler, honeypotServed, redisErrors.


πŸ€– ML Engine Integration

Hippocrates ships with an optional Python sidecar for ML-based threat detection (prompt injection, advanced obfuscation, content risk scoring).

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Hippocrates │────►│  ML Engine   │────►│   Redis   β”‚
β”‚  (Next.js)   β”‚     β”‚  (FastAPI)   β”‚     β”‚ (Upstash) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚                    β”‚
       β”‚  POST /analyze     β”‚
       β”‚  { body_raw, ... } β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Quick Start

# Start both Redis and ML engine
docker compose up -d

# ML engine is now available at http://localhost:8000

Register the plugin in your handler:

import { mlEnginePlugin } from "hippocrates-middleware";

export const POST = withHippocrates(handler, schema, redis, {
  plugins: [mlEnginePlugin({
    baseUrl: "http://ml-engine:8000", // Docker service name
    timeoutMs: 3000,
    minScoreThreshold: 10,
  })],
});

How It Works

  1. After body parsing (post-body phase), the pipeline sends the raw request body to the ML engine
  2. The ML engine runs prompt injection detection, obfuscation scoring, and content risk analysis
  3. Results contribute to the cumulative threat score
  4. If the ML engine is unreachable, it degrades gracefully (score = 0, no crash)

Configuration

Option Default Description
baseUrl http://localhost:8000 ML engine endpoint
timeoutMs 3000 Request timeout before fallback
minScoreThreshold 10 Minimum ML score to contribute to threat score

🐳 Docker Deployment

Run the full Hippocrates stack with a single command:

# docker-compose.yml (included in the package)
services:
  hippocrates-ml-engine:
    build: ./engine-python
    ports:
      - "8000:8000"
    environment:
      - REDIS_URL=redis://redis:6379
    depends_on:
      redis:
        condition: service_healthy

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      retries: 5
# Start services
docker compose up -d

# Run smoke test
powershell -File engine-python/smoke-test.ps1

The ML engine runs on python:3.12-slim with FastAPI + httpx. The Docker build is verified in CI via GitHub Actions.


🌟 Use Cases

Scenario Why Hippocrates
🏒 SaaS APIs Protect B2B/B2C endpoints from LLM scraping agents
πŸ€– AI Startups Prevent competitors from extracting training data
πŸ›’ E-commerce Block automated pricing bots and inventory scrapers
πŸ‘₯ Social Platforms Shadow-ban bot networks probing user data
🏦 Financial Services Halt credential stuffing and enumeration attacks

πŸ§ͺ Testing

npm test                 # 177 tests across 10 files β€” all pass
npm run typecheck        # tsc --noEmit β€” zero errors
npm run lint             # ESLint flat config β€” zero errors
npm run build            # tsup β†’ CJS + ESM + .d.ts

🀝 Contributing

Area How to Help
πŸ› Bug reports Open an issue with reproduction steps
πŸ€– New UA patterns Add it β€” especially 2026+ agents
πŸ” New obfuscation patterns See SKILL.md
⚑ New detection layers Architecture guidance in CLAUDE.md
πŸ“– Documentation Better docs = better adoption

Development

npm run dev              # tsup --watch
npm run build            # Production build
npm run test:watch       # TDD mode

πŸ› οΈ Built With

TypeScript Next.js Redis Zod Vitest tsup Python


πŸ“ˆ Star History

Star History Chart
⭐ Star the repo to show support and help others discover Hippocrates!


β˜• Support

If Hippocrates protects your API, consider supporting development:

GitHub Sponsors Ko-fi Buy Me a Coffee


πŸ“„ License

MIT Β© achmdfzn

First, do no harm β€” to your API.
Built for the era where your API consumers might not be human.

About

🩺 Next.js App Router security middleware β€” silent honeypot that destroys autonomous AI agents, LLM scrapers, and bots using Redis-backed stateful defense. No 403s, no 429s β€” just convincing fake data that wastes attacker compute. Built with Python ML engine.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors