Loading documentation...

Introduction

Guardrail is an open-source security toolkit that provides rate limiting, bot detection, and attack protection for Node.js applications. It runs entirely on your infrastructure with no external dependencies or usage-based pricing.

Key Features

Installation

Install Guardrail using npm or your preferred package manager:

bash
npm install @guardrail-dev/core

For Redis storage support in distributed deployments:

bash
npm install @guardrail-dev/core ioredis

Quick Start

Guardrail is designed to be developer-first. You can start protecting your app with zero configuration:

typescript
import { guardrail } from "@guardrail-dev/core";

// 1. Zero-config (uses API preset + auto-detects Redis)
const gr = guardrail();

export async function POST(req: Request) {
  const decision = await gr.protect(req);
  if (decision.isDenied()) return new Response("Forbidden", { status: 403 });
  return new Response("OK");
}

Next.js Integration

Seamlessly protect your Next.js middleware and API routes.

Middleware

typescript
import { guardrailNext } from "@guardrail-dev/core/next";

// One-liner middleware protection
export const middleware = guardrailNext.api().middleware();

API Routes (App or Pages Router)

typescript
import { protect } from "@guardrail-dev/core/next";

export default protect(async (req, res) => {
  // Secured automatically
  res.json({ success: true });
});

Express.js Integration

Simple middleware factories with semantic presets.

typescript
import express from "express";
import { guardrailExpress } from "@guardrail-dev/core/express";

const app = express();

// Global protection
app.use(guardrailExpress.api());

// Route-specific with custom rules
app.post("/login", guardrailExpress.auth({ debug: true }));

Fastify & Koa

Consistent protection for every major framework.

Fastify

typescript
import { guardrailFastify } from "@guardrail-dev/core/fastify";

fastify.addHook("preHandler", guardrailFastify.api());

Koa

typescript
import { guardrailKoa } from "@guardrail-dev/core/koa";

app.use(guardrailKoa.web());

Nest.js Integration

Register Guardrail as a module and use the ultimate decorator-driven security experience.

Module Registration

typescript
import { Module } from "@nestjs/common";
import { GuardrailModule } from "@guardrail-dev/core/nestjs";

@Module({
  imports: [
    GuardrailModule.forRoot({
      autoProtect: true, // Automatically protect every route
      useGuard: true,
    }),
  ],
})
export class AppModule {}

Ultimate Decorators

Add protection to specific controllers or routes with single-line decorators:

typescript
import { Controller, Post } from "@nestjs/common";
import { Limit, Shield, BlockVPN, Result } from "@guardrail-dev/core/nestjs";

@Controller("payments")
@Shield() // Protect all routes in this controller
export class PaymentsController {
  @Post()
  @Limit({ max: 5, interval: "1m" }) // Override rate limit
  @BlockVPN() // Shortcut for VPN blocking
  async process(@Result() decision: Decision) {
    return { id: decision.id };
  }
}

Rules Overview

Guardrail uses a rule-based system to evaluate requests. Rules are evaluated in order, and each rule returns an ALLOW or DENY decision.

Rule Description Import
shield Attack protection (SQL injection, XSS, etc.) shield()
bot Bot detection and blocking bot({ allow: [] })
window Rate limiting with sliding window window({ interval, max })
bucket Rate limiting with token bucket bucket({ capacity, refillRate })
email Email validation and blocking email({ block: [...] })
filter Expression-based filtering filter({ deny: [...] })

Rate Limiting

Sliding Window

Limit the number of requests within a time window:

typescript
import { window } from "@guardrail-dev/core";

window({
  interval: "10m",  // Time window
  max: 100,          // Maximum requests
});

Token Bucket

For more complex rate limiting, especially useful for AI quota control:

typescript
import { bucket } from "@guardrail-dev/core";

bucket({
  by: ["userId"],  // Rate limit per user
  refillRate: 2000,             // Tokens added per interval
  interval: "1h",               // Refill interval
  capacity: 5000,               // Maximum token capacity
});

// Usage with token consumption
const decision = await gr.protect(req, {
  userId: "user123",
  requested: estimatedTokens,
});

if (decision.reason.isQuota()) {
  const remaining = decision.reason.getRemaining();
  console.log(`Tokens remaining: ${remaining}`);
}

Bot Detection

Detect and block automated traffic while allowing specific bots:

typescript
import { bot } from "@guardrail-dev/core";

// Block all bots
bot({ allow: [] });

// Allow specific bots
bot({
  allow: ["Googlebot", "Bingbot", "Slackbot"],
});

Shield (Attack Protection)

Protect against common web attacks:

typescript
import { shield } from "@guardrail-dev/core";

// Default protection
shield();

// Dry run mode (log but don't block)
shield({ mode: "DRY_RUN" });

Shield protects against:

  • SQL injection attacks
  • Cross-site scripting (XSS)
  • Command injection
  • Path traversal

Email Validation

Block problematic email addresses:

typescript
import { email } from "@guardrail-dev/core";

email({
  block: [
    "DISPOSABLE",    // Temporary email services
    "INVALID",       // Invalid format
    "NO_MX_RECORDS", // No mail server
    "FREE",          // Free email providers
  ],
});

// Usage
const decision = await gr.protect(req, {
  email: "user@example.com",
});

Filter Rules

Create custom filters using expressions:

typescript
import { filter } from "@guardrail-dev/core";

// Block non-US traffic
filter({
  deny: ['ip.src.country ne "US"'],
});

// Allow only specific IPs
filter({
  allow: ["ip.src in { 1.2.3.4 5.6.7.8 }"],
});

// Complex expressions
filter({
  deny: [
    "ip.src.vpn == true",
    'ip.src.country in ["XX", "YY"]',
    'ip.src.country ne "US" and ip.src.proxy == true',
  ],
});

Supported Operators

Operator Description Example
==, != Equality comparison ip.src.vpn == true
>, <, >=, <= Numeric comparison request.count > 100
in Membership check ip.src.country in ["US", "CA"]
and, or, not Logical operators vpn == true and proxy == true
matches Regex matching path matches "^/api/"

IP Intelligence

Access detailed IP information for every request:

typescript
const decision = await gr.protect(req);

// Geolocation
if (decision.ip.hasCountry()) {
  console.log(decision.ip.country);     // "US"
  console.log(decision.ip.countryName); // "United States"
}

if (decision.ip.hasRegion()) {
  console.log(decision.ip.region);      // "California"
}

if (decision.ip.hasCity()) {
  console.log(decision.ip.city);        // "San Francisco"
}

// Network detection
if (decision.ip.isVpn()) {
  console.log("VPN detected");
}

if (decision.ip.isProxy()) {
  console.log("Proxy detected");
}

if (decision.ip.isHosting()) {
  console.log("Hosting provider detected");
}

Premium IP Providers

For production environments, we recommend using dedicated IP intelligence providers for higher accuracy and rate limits.

MaxMind GeoIP2

typescript
import { guardrail, MaxMindProvider } from "@guardrail-dev/core";

const gr = guardrail({
  ipService: new MaxMindProvider({
    accountId: process.env.MAXMIND_ACCOUNT_ID,
    licenseKey: process.env.MAXMIND_LICENSE_KEY,
    serviceType: "insights", // "country", "city", or "insights"
  }),
  rules: [/* ... */],
});

IPinfo.io

typescript
import { guardrail, IPinfoProvider } from "@guardrail-dev/core";

const gr = guardrail({
  ipService: new IPinfoProvider({
    token: process.env.IPINFO_TOKEN,
  }),
  rules: [/* ... */],
});

Fallback Strategy

Chain multiple providers to ensure high availability:

typescript
import { guardrail, FallbackIPProvider, MaxMindProvider, IPinfoProvider } from "@guardrail-dev/core";

const gr = guardrail({
  ipService: new FallbackIPProvider([
    new MaxMindProvider({ /* ... */ }),
    new IPinfoProvider({ /* ... */ }),
  ]),
  rules: [/* ... */],
});

Standalone VPN/Proxy Detection

Use the advanced VPN detection logic independently of the main guardrail pipeline:

typescript
import { VPNProxyDetection } from "@guardrail-dev/core";

const vpnDetector = new VPNProxyDetection({
  enableHeuristicDetection: true,
  confidenceThreshold: 50,
  customVPNProviders: ["my-internal-vpn"],
});

// Check an IP
const result = await vpnDetector.check("1.2.3.4");
if (result.isVpn) {
  console.log("VPN detected via:", result.method);
}

// Get detection statistics
console.log(vpnDetector.getProviderCounts());

Storage Backends

Memory Storage

Default storage for single-instance deployments:

typescript
import { guardrail, MemoryStorage } from "@guardrail-dev/core";

const gr = guardrail({
  storage: new MemoryStorage(10000),  // Max cache size
  rules: [/* ... */],
});

Redis Storage

For distributed deployments with multiple instances:

typescript
import { guardrail, RedisStorage } from "@guardrail-dev/core";

const gr = guardrail({
  storage: new RedisStorage(process.env.REDIS_URL),
  rules: [/* ... */],
});

Configuration

typescript
const gr = guardrail({
  rules: [/* ... */],

  // Error handling mode
  errorHandling: "FAIL_CLOSED",  // or "FAIL_OPEN" (default)

  // Evaluation strategy
  evaluationStrategy: "PARALLEL",  // or "SEQUENTIAL", "SHORT_CIRCUIT"

  // Debug mode
  debug: true,

  // Whitelist
  whitelist: {
    ips: ["1.2.3.4"],
    userIds: ["admin"],
    countries: ["US", "CA"],
  },

  // Blacklist
  blacklist: {
    ips: ["5.6.7.8"],
    countries: ["XX"],
  },
});

Error Handling Modes

  • FAIL_OPEN (default) — On errors, allow requests through
  • FAIL_CLOSED — On errors, deny requests (more secure)

Evaluation Strategies

  • SEQUENTIAL (default) — Evaluate rules one by one
  • PARALLEL — Evaluate all rules simultaneously
  • SHORT_CIRCUIT — Stop on first DENY decision

Metrics & Events

Metrics Collection

typescript
const gr = guardrail({
  rules: [/* ... */],
  debug: true,
});

// Get metrics
const metrics = gr.getMetrics();
console.log(metrics.getMetrics());

// Available metrics:
// - guardrail.requests.total
// - guardrail.decisions.allowed
// - guardrail.decisions.denied
// - guardrail.request.duration
// - guardrail.rule.{ruleType}.duration

Event System

typescript
gr.on("decision.denied", (event) => {
  console.log("Denied:", event.decision);
});

gr.on("rule.evaluate", (event) => {
  console.log("Evaluating:", event.ruleType);
});

// Available events:
// - rule.evaluate
// - rule.allow
// - rule.deny
// - decision.allowed
// - decision.denied
// - storage.error
// - ip-lookup.error

API Reference

guardrail(config)

Creates a new Guardrail instance.

Option Type Description
rules Array Array of rule configurations (required)
storage Storage Storage adapter (default: MemoryStorage)
ipService IPService IP geolocation service
errorHandling String "FAIL_OPEN" or "FAIL_CLOSED"
evaluationStrategy String "SEQUENTIAL", "PARALLEL", or "SHORT_CIRCUIT"
debug Boolean Enable debug mode and metrics
whitelist Object Whitelist configuration
blacklist Object Blacklist configuration

protect(request, options?)

Evaluates a request against all configured rules and returns a decision.

Option Type Description
userId String User identifier for rate limiting
email String Email address for validation
requested Number Number of tokens/requests requested

Examples

Payment Form Protection

typescript
const gr = guardrail({
  rules: [
    shield(),
    bot({ allow: [] }),
    email({
      block: ["DISPOSABLE", "INVALID", "NO_MX_RECORDS"],
    }),
    window({ interval: "10m", max: 5 }),
  ],
  whitelist: {
    ips: ["1.2.3.4"],  // Admin IP
  },
});

export async function POST(req: Request) {
  const { email } = await req.json();
  const decision = await gr.protect(req, { email });

  if (decision.isDenied()) {
    if (decision.reason.isBot()) {
      return new Response("Bot detected", { status: 403 });
    }
    if (decision.reason.isEmail()) {
      return new Response("Invalid email", { status: 400 });
    }
    if (decision.reason.isRateLimit()) {
      return new Response("Rate limit exceeded", { status: 429 });
    }
  }

  // Process payment
  return new Response("Payment processed");
}

AI Quota Control

typescript
const gr = guardrail({
  rules: [
    bucket({
      by: ["userId"],
      refillRate: 2000,
      interval: "1h",
      capacity: 5000,
    }),
  ],
  evaluationStrategy: "SHORT_CIRCUIT",
});

export async function POST(req: Request) {
  const { userId, prompt } = await req.json();
  const estimatedTokens = estimateTokens(prompt);

  const decision = await gr.protect(req, {
    userId,
    requested: estimatedTokens,
  });

  if (decision.reason.isQuota()) {
    const remaining = decision.reason.getRemaining();
    return Response.json(
      { error: "Quota exceeded", remaining },
      { status: 429 }
    );
  }

  // Process AI request
  return Response.json({ success: true });
}

Testing

Guardrail includes testing utilities for unit and integration tests:

typescript
import { createTestGuardrail } from "@guardrail-dev/core/testing";
import { shield, window } from "@guardrail-dev/core";

const { guardrail, storage, ipService } = createTestGuardrail({
  rules: [
    shield(),
    window({ interval: "1m", max: 100 }),
  ],
});

// Mock IP data
ipService.setIP("1.2.3.4", {
  country: "US",
  countryName: "United States",
  city: "San Francisco",
});

// Test your code
const decision = await guardrail.protect(req);
expect(decision.isAllowed()).toBe(true);

Known Limitations

IP Geolocation

  • Default provider uses free APIs with rate limits (ipapi.co: 1000/day, ip-api.com: 45/min)
  • Recommendation: Use MaxMindProvider, IPinfoProvider, or IPQualityScoreProvider for production

VPN/Proxy Detection

  • Detection is based on ASN name matching against a comprehensive (100+) but not exhaustive list
  • Recommendation: Use IPQualityScoreProvider for advanced fraud detection

Bot Detection

  • Basic detection uses User-Agent matching only
  • Recommendation: Use bot() with configuration for header analysis and behavioral signals
  • Client-side fingerprinting requires a separate implementation

Rate Limiting

  • MemoryStorage does not sync across Node.js cluster workers
  • Recommendation: Use AtomicRedisStorage for distributed deployments

Attack Protection

  • Guardrail is not a replacement for enterprise WAF solutions (Cloudflare, AWS WAF)