npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@leakguard/webhook

v3.0.2

Published

Secure webhook verification with minimal overhead

Readme

@leakguard/webhook

🔒 Secure webhook verification with minimal overhead

Verify incoming webhooks from providers like Stripe, GitHub, Zapier, and more with production-grade security and framework-agnostic design.

Why @leakguard/webhook?

The Problem

Webhooks are a critical attack vector. Without proper verification:

  • Spoofed requests can trigger unauthorized actions
  • Replay attacks can cause duplicate processing
  • Unauthorized access to webhook endpoints
  • Data integrity cannot be guaranteed

Why It's Hard

  • Cryptographic complexity: HMAC verification, timing attacks, signature formats
  • Provider variations: Each service has different header formats and algorithms
  • Framework integration: Request body handling varies across Express, Fastify, NestJS
  • Edge cases: Encoding issues, missing headers, malformed signatures

Why Not Roll Your Own?

// ❌ Vulnerable to timing attacks
if (providedSignature !== expectedSignature) {
  return res.status(401).send('Invalid');
}

// ❌ Improper signature parsing
const signature = header.split('=')[1]; // Breaks on complex formats

// ❌ Missing replay protection
// No timestamp validation or duplicate detection

// ✅ LeakGuard handles all of this correctly

Installation

npm install @leakguard/webhook

# Peer dependencies for specific frameworks
npm install express @types/express          # For Express
npm install fastify                         # For Fastify  
npm install @nestjs/common @nestjs/core     # For NestJS

Quick Start

Express

import express from 'express';
import { createStripeStrategy, expressWebhookVerify, expressRawBody } from '@leakguard/webhook';

const app = express();

// Important: Use rawBody middleware for HMAC verification
app.use('/webhooks', expressRawBody());

// Verify Stripe webhooks
app.use('/webhooks/stripe', expressWebhookVerify({
  strategies: [createStripeStrategy(process.env.STRIPE_WEBHOOK_SECRET!)]
}));

app.post('/webhooks/stripe', (req, res) => {
  // Webhook is verified ✅
  const event = req.body;
  console.log('Verified Stripe event:', event.type);
  res.sendStatus(200);
});

NestJS

import { Controller, Post, UseGuards, MiddlewareConsumer, Module } from '@nestjs/common';
import { 
  WebhookVerificationGuard, 
  RawBodyMiddleware,
  createStripeStrategy 
} from '@leakguard/webhook';

@Controller('webhooks')
export class WebhookController {
  @Post('stripe')
  @UseGuards(new WebhookVerificationGuard({
    strategies: [createStripeStrategy(process.env.STRIPE_WEBHOOK_SECRET!)]
  }))
  handleStripeWebhook(@Req() req: Request) {
    // Webhook is verified ✅
    console.log('Verification metadata:', req.webhookVerification);
    return { received: true };
  }
}

@Module({
  controllers: [WebhookController]
})
export class WebhookModule {
  configure(consumer: MiddlewareConsumer) {
    // Apply raw body middleware to webhook routes
    consumer.apply(RawBodyMiddleware).forRoutes('webhooks/*');
  }
}

Fastify

import fastify from 'fastify';
import { fastifyWebhookVerify, createGitHubStrategy } from '@leakguard/webhook';

const app = fastify();

// Register webhook verification plugin
await app.register(fastifyWebhookVerify, {
  webhook: {
    strategies: [createGitHubStrategy(process.env.GITHUB_WEBHOOK_SECRET!)],
    routes: ['/webhooks/github']
  }
});

app.post('/webhooks/github', async (request, reply) => {
  // Webhook is verified ✅
  const payload = request.body;
  console.log('GitHub event:', payload);
  return { received: true };
});

Verification Strategies

HMAC Signature Verification

Verify cryptographic signatures using HMAC algorithms:

import { HMACStrategy } from '@leakguard/webhook';

const strategy = new HMACStrategy({
  secret: 'your-webhook-secret',
  algorithm: 'sha256',           // sha1, sha256, sha512
  headerName: 'x-signature-256',
  signaturePrefix: 'sha256=',
  tolerance: 300                 // 5 minutes timestamp tolerance
});

Token-based Verification

Verify static tokens or API keys:

import { TokenStrategy } from '@leakguard/webhook';

const strategy = new TokenStrategy({
  token: 'your-webhook-token',
  headerName: 'authorization',    // or 'x-api-key', etc.
  queryParam: 'token'            // Optional: also check query params
});

// Supports Bearer token format
// Header: "Authorization: Bearer your-webhook-token"

IP Allowlist Verification

Restrict webhooks to specific IP addresses or CIDR ranges:

import { IPWhitelistStrategy } from '@leakguard/webhook';

const strategy = new IPWhitelistStrategy({
  allowedIPs: [
    '192.168.1.1',      // Single IP
    '10.0.0.0/8',       // CIDR range
    '172.16.0.0/12'
  ],
  trustProxy: true      // Trust X-Forwarded-For headers
});

Custom Verification

Implement your own verification logic:

import { CustomStrategy } from '@leakguard/webhook';

const strategy = new CustomStrategy(async (request) => {
  // Your custom logic here
  const isValid = await yourVerificationLogic(request);
  
  return {
    verified: isValid,
    error: isValid ? undefined : 'Custom verification failed',
    metadata: { customField: 'value' }
  };
});

Provider Presets

Pre-configured strategies for popular webhook providers:

Stripe

import { createStripeStrategy } from '@leakguard/webhook';

const strategy = createStripeStrategy(
  process.env.STRIPE_WEBHOOK_SECRET!,
  300 // Optional: timestamp tolerance in seconds
);

// Handles Stripe's signature format:
// stripe-signature: t=1640995200,v1=abc123...

GitHub

import { 
  createGitHubStrategy, 
  createGitHubLegacyStrategy 
} from '@leakguard/webhook';

// Modern GitHub webhooks (SHA-256)
const strategy = createGitHubStrategy(process.env.GITHUB_WEBHOOK_SECRET!);

// Legacy GitHub webhooks (SHA-1) 
const legacyStrategy = createGitHubLegacyStrategy(process.env.GITHUB_WEBHOOK_SECRET!);

Zapier

import { createZapierStrategy } from '@leakguard/webhook';

const strategy = createZapierStrategy(process.env.ZAPIER_TOKEN!);

Webflow

import { createWebflowStrategy } from '@leakguard/webhook';

const strategy = createWebflowStrategy(process.env.WEBFLOW_SECRET!);

Slack

import { createSlackStrategy } from '@leakguard/webhook';

const strategy = createSlackStrategy(
  process.env.SLACK_SIGNING_SECRET!,
  300 // Timestamp tolerance
);

Discord & Twilio (IP-based)

import { createDiscordStrategy, createTwilioStrategy } from '@leakguard/webhook';

// Discord webhooks (IP allowlist)
const discordStrategy = createDiscordStrategy();

// Twilio webhooks (IP allowlist)  
const twilioStrategy = createTwilioStrategy();

Shopify & E-commerce

import { createShopifyStrategy, createSquareStrategy, createLemonSqueezyStrategy } from '@leakguard/webhook';

// Shopify webhooks
const shopifyStrategy = createShopifyStrategy(process.env.SHOPIFY_SECRET!);

// Square webhooks
const squareStrategy = createSquareStrategy(process.env.SQUARE_SIGNATURE_KEY!);

// LemonSqueezy webhooks
const lemonSqueezyStrategy = createLemonSqueezyStrategy(process.env.LEMONSQUEEZY_SECRET!);

Developer & DevOps Tools

import { 
  createGitLabStrategy, 
  createBitbucketStrategy,
  createCircleCIStrategy,
  createVercelStrategy,
  createNetlifyStrategy 
} from '@leakguard/webhook';

// GitLab webhooks
const gitlabStrategy = createGitLabStrategy(process.env.GITLAB_TOKEN!);

// Bitbucket webhooks  
const bitbucketStrategy = createBitbucketStrategy(process.env.BITBUCKET_SECRET!);

// CircleCI webhooks
const circleciStrategy = createCircleCIStrategy(process.env.CIRCLECI_SECRET!);

// Vercel webhooks
const vercelStrategy = createVercelStrategy(process.env.VERCEL_SECRET!);

// Netlify webhooks
const netlifyStrategy = createNetlifyStrategy(process.env.NETLIFY_SECRET!);

Productivity & CRM Tools

import { 
  createLinearStrategy,
  createNotionStrategy,
  createAsanaStrategy,
  createAirtableStrategy,
  createCalendlyStrategy,
  createFigmaStrategy 
} from '@leakguard/webhook';

// Linear webhooks
const linearStrategy = createLinearStrategy(process.env.LINEAR_SECRET!);

// Notion webhooks
const notionStrategy = createNotionStrategy(process.env.NOTION_SECRET!);

// Asana webhooks
const asanaStrategy = createAsanaStrategy(process.env.ASANA_SECRET!);

// Airtable webhooks
const airtableStrategy = createAirtableStrategy(process.env.AIRTABLE_SECRET!);

// Calendly webhooks
const calendlyStrategy = createCalendlyStrategy(process.env.CALENDLY_SECRET!);

// Figma webhooks
const figmaStrategy = createFigmaStrategy(process.env.FIGMA_SECRET!);

Email & Communication

import { 
  createSendGridStrategy,
  createMailgunStrategy,
  createIntercomStrategy,
  createHubSpotStrategy 
} from '@leakguard/webhook';

// SendGrid webhooks
const sendgridStrategy = createSendGridStrategy(process.env.SENDGRID_SECRET!);

// Mailgun webhooks
const mailgunStrategy = createMailgunStrategy(process.env.MAILGUN_SIGNING_KEY!);

// Intercom webhooks
const intercomStrategy = createIntercomStrategy(process.env.INTERCOM_SECRET!);

// HubSpot webhooks
const hubspotStrategy = createHubSpotStrategy(process.env.HUBSPOT_SECRET!);

Enterprise & Support

import { 
  createSalesforceStrategy,
  createZendeskStrategy,
  createDocuSignStrategy,
  createDropboxStrategy,
  createBoxStrategy 
} from '@leakguard/webhook';

// Salesforce webhooks
const salesforceStrategy = createSalesforceStrategy(process.env.SALESFORCE_SECRET!);

// Zendesk webhooks
const zendeskStrategy = createZendeskStrategy(process.env.ZENDESK_SECRET!);

// DocuSign webhooks
const docusignStrategy = createDocuSignStrategy(process.env.DOCUSIGN_SECRET!);

// Dropbox webhooks
const dropboxStrategy = createDropboxStrategy(process.env.DROPBOX_SECRET!);

// Box webhooks
const boxStrategy = createBoxStrategy(process.env.BOX_SECRET!);

Multiple Providers

import { createProviderStrategies } from '@leakguard/webhook';

const strategies = createProviderStrategies({
  stripe: { secret: process.env.STRIPE_SECRET! },
  github: { secret: process.env.GITHUB_SECRET! },
  shopify: { secret: process.env.SHOPIFY_SECRET! },
  linear: { secret: process.env.LINEAR_SECRET! },
  sendgrid: { secret: process.env.SENDGRID_SECRET! },
  vercel: { secret: process.env.VERCEL_SECRET! }
});

Configuration Options

Multiple Strategies

Combine multiple verification strategies:

const config = {
  strategies: [
    createStripeStrategy(stripeSecret),
    new TokenStrategy({ token: backupToken }),
    new IPWhitelistStrategy({ allowedIPs: ['trusted-ip'] })
  ],
  
  // Require ALL strategies to pass (default: false)
  requireAll: true,
  
  // Stateless timestamp validation (mitigates many replay attacks)
  timestampValidation: {
    timestampHeader: 'x-timestamp',
    tolerance: 300,
    timestampFormat: 'unix' // or 'iso'
  },
  
  // Event handlers
  onSuccess: (request) => {
    console.log('Webhook verified successfully');
  },
  
  onFailure: (result, request) => {
    console.error('Webhook verification failed:', result.error);
  }
};

Framework-Specific Options

Express Options

const expressConfig = {
  strategies: [/* your strategies */],
  
  skipRoutes: ['/health', '/metrics'],    // Skip verification
  skipMethods: ['GET', 'OPTIONS'],        // Skip HTTP methods
  
  onFailure: (error, req, res, next) => {
    // Custom error handling
    res.status(401).json({ 
      error: 'Webhook verification failed',
      details: error 
    });
  },
  
  onSuccess: (req, res, next) => {
    // Custom success handling
    req.customField = 'verified';
    next();
  }
};

NestJS Options

const nestConfig = {
  strategies: [/* your strategies */],
  skipRoutes: ['/health'],
  skipMethods: ['GET']
};

// Use as Guard
@UseGuards(new WebhookVerificationGuard(nestConfig))

// Use as Middleware
export class ConfiguredMiddleware extends WebhookVerificationMiddleware {
  constructor() {
    super(nestConfig);
  }
}

Fastify Options

const fastifyConfig = {
  webhook: {
    strategies: [/* your strategies */],
    routes: ['/webhooks/*'],  // Apply only to specific routes
    
    onFailure: (error, request, reply) => {
      reply.code(401).send({ error });
    },
    
    onSuccess: (request, reply) => {
      // Custom success logic
    }
  }
};

Stateless Security Architecture

Why Stateless?

This package is designed for modern deployment patterns:

  • Serverless functions (AWS Lambda, Vercel, Cloudflare Workers)
  • Kubernetes autoscaling with ephemeral pods
  • Docker containers without persistent storage
  • Multi-region deployments without shared state

Replay Protection Strategy

What we provide

  • Timestamp validation: Rejects requests older than X seconds
  • Signature verification: Cryptographic integrity protection
  • IP allowlisting: Restrict to known sources
  • Timing-safe comparisons: Prevent timing attacks
const config = {
  strategies: [createStripeStrategy(secret)],
  
  // Stateless replay mitigation
  timestampValidation: {
    timestampHeader: 'x-timestamp',
    tolerance: 300, // 5 minutes - adjust based on your needs
    timestampFormat: 'unix'
  }
};

What we DON'T provide

  • Perfect replay protection: Requires external storage (Redis/DB)
  • Request deduplication: Would break stateless architecture
  • Global nonce tracking: Incompatible with autoscaling

When You Need Full Replay Protection

If your application requires perfect replay protection:

// Option 1: Add your own request tracking
const processedRequests = new Set(); // Or Redis/DB

app.use('/webhook', (req, res, next) => {
  const requestId = createRequestId(req);
  
  if (processedRequests.has(requestId)) {
    return res.status(409).send('Duplicate request');
  }
  
  processedRequests.add(requestId);
  next();
});

// Option 2: Use provider-specific replay protection
// Many providers (Stripe, GitHub) include their own replay protection

// Option 3: Accept the tradeoff
// For many use cases, timestamp validation is sufficient

Security vs Scalability Tradeoffs

| Approach | Replay Protection | Scalability | Complexity | |----------|------------------|-------------|------------| | Stateless (LeakGuard) | Good | Excellent | Low | | Redis/DB tracking | Perfect | Good | Medium | | Provider built-in | Perfect | Excellent | Low |

Security Best Practices

1. Always Use Raw Body for HMAC

// ✅ Correct - Raw body preserved
app.use('/webhooks', rawBody());
app.use('/webhooks', webhookVerify({ ... }));

// ❌ Wrong - Body already parsed
app.use(express.json());
app.use('/webhooks', webhookVerify({ ... }));

2. Use HTTPS Only

// ✅ Force HTTPS in production
app.use((req, res, next) => {
  if (req.header('x-forwarded-proto') !== 'https') {
    return res.redirect(`https://${req.header('host')}${req.url}`);
  }
  next();
});

3. Implement Rate Limiting

import rateLimit from 'express-rate-limit';

// ✅ Rate limit webhook endpoints
const webhookLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100 // limit each IP to 100 requests per windowMs
});

app.use('/webhooks', webhookLimiter);

4. Use Different Secrets Per Provider

// ✅ Separate secrets for each provider
const strategies = [
  createStripeStrategy(process.env.STRIPE_WEBHOOK_SECRET),
  createGitHubStrategy(process.env.GITHUB_WEBHOOK_SECRET),
  // Don't reuse secrets across providers
];

5. Enable Timestamp Validation

// ✅ Enable timestamp validation for time-sensitive webhooks
const config = {
  strategies: [strategy],
  timestampValidation: {
    timestampHeader: 'x-timestamp',
    tolerance: 300 // 5 minutes
  }
};

Performance

Benchmarks

  • HMAC (small payload): ~50,000 ops/sec
  • HMAC (large payload): ~5,000 ops/sec
  • Token verification: ~100,000+ ops/sec
  • IP allowlist: ~150,000+ ops/sec
  • Multiple strategies: ~20,000 ops/sec

Optimization Tips

  1. Use specific strategies: Avoid unnecessary verification steps
  2. Order strategies by speed: Fast strategies first when using requireAll: false
  3. Enable replay protection selectively: Only for time-sensitive webhooks
  4. Use IP allowlisting when possible: Fastest verification method
// ✅ Optimized configuration
const config = {
  strategies: [
    // Fast strategies first
    new IPWhitelistStrategy({ allowedIPs: ['trusted-range'] }),
    new TokenStrategy({ token: 'backup-token' }),
    // Slower HMAC verification last
    new HMACStrategy({ secret: 'hmac-secret' })
  ],
  requireAll: false // Exit early on first success
};

Troubleshooting

Common Issues

1. HMAC Verification Fails

// Check these common issues:

// ✅ Ensure raw body is available
console.log('Raw body type:', typeof request.rawBody);
console.log('Raw body length:', request.rawBody?.length);

// ✅ Check signature header format
console.log('Signature header:', request.headers['x-signature']);

// ✅ Verify secret is correct
console.log('Secret (first 4 chars):', secret.substring(0, 4));

// ✅ Check algorithm matches provider
const strategy = new HMACStrategy({
  secret: 'correct-secret',
  algorithm: 'sha256', // Make sure this matches provider
  headerName: 'x-hub-signature-256',
  signaturePrefix: 'sha256='
});

2. Missing Headers

// ✅ Handle missing headers gracefully
const config = {
  strategies: [strategy],
  onFailure: (result, request) => {
    console.log('Available headers:', Object.keys(request.headers));
    console.log('Failure reason:', result.error);
  }
};

3. Timestamp Issues

// ✅ Debug timestamp validation
const config = {
  timestampValidation: {
    timestampHeader: 'x-timestamp',
    tolerance: 600, // Increase tolerance temporarily
    timestampFormat: 'unix'
  },
  onFailure: (result) => {
    console.log('Current time:', Math.floor(Date.now() / 1000));
    console.log('Request timestamp:', /* extract from headers */);
  }
};

Error Handling

Custom Error Responses

// Express custom error handling
app.use('/webhooks', webhookVerify({
  strategies: [strategy],
  onFailure: (error, req, res, next) => {
    // Log for debugging
    console.error('Webhook verification failed:', {
      error,
      headers: req.headers,
      ip: req.ip,
      url: req.url
    });
    
    // Return generic error (don't leak verification details)
    res.status(401).json({
      error: 'Unauthorized',
      timestamp: new Date().toISOString()
    });
  }
}));

// NestJS exception handling
@UseGuards(new WebhookVerificationGuard(config))
@Post('webhook')
async handleWebhook(@Req() req: Request) {
  try {
    // Process webhook
    return { success: true };
  } catch (error) {
    // Webhook was verified, but processing failed
    throw new InternalServerErrorException('Webhook processing failed');
  }
}

API Reference

Core Types

interface WebhookRequest {
  headers: Record<string, string | string[] | undefined>;
  body: Buffer | string;
  rawBody?: Buffer;
  ip?: string;
}

interface VerificationResult {
  verified: boolean;
  error?: string;
  metadata?: Record<string, unknown>;
}

interface WebhookConfig {
  strategies: VerificationStrategy[];
  requireAll?: boolean;
  timestampValidation?: TimestampValidationOptions;
  onFailure?: (result: VerificationResult, request: WebhookRequest) => void;
  onSuccess?: (request: WebhookRequest) => void;
}

Strategy Classes

  • HMACStrategy(options: HMACOptions)
  • TokenStrategy(options: TokenOptions)
  • IPWhitelistStrategy(options: IPWhitelistOptions)
  • CustomStrategy(verifyFn: CustomVerificationFunction)

Provider Functions

  • createStripeStrategy(secret: string, tolerance?: number)
  • createGitHubStrategy(secret: string)
  • createZapierStrategy(token: string)
  • createWebflowStrategy(secret: string)
  • createSlackStrategy(secret: string, tolerance?: number)
  • createDiscordStrategy()
  • createTwilioStrategy()

Framework Adapters

  • expressWebhookVerify(config: ExpressWebhookOptions)
  • expressRawBody()
  • fastifyWebhookVerify
  • WebhookVerificationGuard (NestJS)
  • WebhookVerificationMiddleware (NestJS)

Examples

Multi-Provider Webhook Handler

import express from 'express';
import { 
  createStripeStrategy,
  createGitHubStrategy,
  createZapierStrategy,
  expressWebhookVerify,
  expressRawBody
} from '@leakguard/webhook';

const app = express();

// Global raw body middleware
app.use('/webhooks', expressRawBody());

// Stripe webhooks
app.use('/webhooks/stripe', expressWebhookVerify({
  strategies: [createStripeStrategy(process.env.STRIPE_WEBHOOK_SECRET!)]
}));

app.post('/webhooks/stripe', (req, res) => {
  const event = req.body;
  console.log('Stripe event:', event.type);
  
  switch (event.type) {
    case 'payment_intent.succeeded':
      // Handle payment success
      break;
    case 'customer.subscription.deleted':
      // Handle subscription cancellation  
      break;
  }
  
  res.sendStatus(200);
});

// GitHub webhooks
app.use('/webhooks/github', expressWebhookVerify({
  strategies: [createGitHubStrategy(process.env.GITHUB_WEBHOOK_SECRET!)]
}));

app.post('/webhooks/github', (req, res) => {
  const event = req.headers['x-github-event'];
  const payload = req.body;
  
  console.log('GitHub event:', event);
  
  if (event === 'push') {
    // Handle repository push
  }
  
  res.sendStatus(200);
});

// Zapier webhooks (token-based)
app.use('/webhooks/zapier', expressWebhookVerify({
  strategies: [createZapierStrategy(process.env.ZAPIER_TOKEN!)]
}));

app.post('/webhooks/zapier', (req, res) => {
  console.log('Zapier payload:', req.body);
  res.sendStatus(200);
});

High-Security Configuration

import { 
  HMACStrategy,
  TokenStrategy,
  IPWhitelistStrategy,
  expressWebhookVerify 
} from '@leakguard/webhook';

// Multi-layer verification
const highSecurityConfig = {
  strategies: [
    // Layer 1: IP allowlist
    new IPWhitelistStrategy({
      allowedIPs: ['trusted-cidr-range/24'],
      trustProxy: true
    }),
    
    // Layer 2: Token verification  
    new TokenStrategy({
      token: process.env.BACKUP_TOKEN!,
      headerName: 'x-api-key'
    }),
    
    // Layer 3: HMAC signature
    new HMACStrategy({
      secret: process.env.HMAC_SECRET!,
      algorithm: 'sha256',
      headerName: 'x-signature-256'
    })
  ],
  
  // Require ALL strategies to pass
  requireAll: true,
  
  // Strict replay protection
  replayProtection: {
    timestampHeader: 'x-timestamp',
    tolerance: 60, // 1 minute window
    timestampFormat: 'unix'
  },
  
  onFailure: (result, request) => {
    // Log security events
    console.error('Security violation:', {
      error: result.error,
      ip: request.ip,
      timestamp: new Date().toISOString(),
      headers: request.headers
    });
  }
};

app.use('/webhooks/critical', expressWebhookVerify(highSecurityConfig));

License

MIT - see LICENSE for details.