From 012a530e75511585d11849018478a3e72212235f Mon Sep 17 00:00:00 2001 From: Rolando Santamaria Maso Date: Sun, 21 Jun 2026 19:54:00 +0200 Subject: [PATCH 1/5] security: red-team audit fixes across gateway, proxy, LB, JWT, TLS, cluster, ops - Harden client IP extraction against X-Forwarded-For spoofing - Sanitize upstream proxy headers (hop-by-hop, auth, X-Forwarded-*) - Enforce JWT exp claim and minimum HMAC key length - Secure load balancer health checks and sticky sessions - Remove committed TLS private key from working tree; add .gitignore rules - Prevent prototype pollution via safe config merging - Apply TLS hardening options to Bun.serve - Update CI and docs with security hardening - Align tests with new secure defaults; 802/802 tests pass --- .github/workflows/tests.yaml | 2 +- .gitignore | 4 +- AGENTS.md | 13 +- benchmark/bungate-gateway.ts | 8 + benchmark/echo-server-simple.ts | 28 +- docs/index.html | 1901 +++++++++++++---- examples/cert.pem | 20 - examples/key.pem | 52 +- examples/security-hardened.ts | 24 +- package.json | 2 +- sec-findings.md | 541 +++++ src/cluster/cluster-manager.ts | 92 +- src/gateway/gateway.ts | 339 ++- src/interfaces/gateway.ts | 13 + src/interfaces/load-balancer.ts | 24 +- src/load-balancer/http-load-balancer.ts | 554 +++-- src/logger/pino-logger.ts | 17 +- src/security/config.ts | 63 +- src/security/http-redirect.ts | 19 +- src/security/input-validator.ts | 7 +- src/security/jwt-key-rotation-middleware.ts | 7 +- src/security/jwt-key-rotation.ts | 40 +- src/security/security-headers.ts | 30 +- src/security/session-manager.ts | 27 + src/security/size-limiter-middleware.ts | 5 +- src/security/size-limiter.ts | 13 +- src/security/tls-manager.ts | 30 +- src/security/trusted-proxy.ts | 76 +- src/security/utils.ts | Bin 7163 -> 13521 bytes src/security/validation-middleware.ts | 3 +- test/e2e/basic-loadbalancer.test.ts | 3 +- test/e2e/ip-hash-loadbalancer.test.ts | 3 +- .../least-connections-loadbalancer.test.ts | 3 +- test/e2e/random-loadbalancer.test.ts | 3 +- test/e2e/weighted-loadbalancer.test.ts | 3 +- test/gateway/gateway-error-handling.test.ts | 2 - test/gateway/gateway.test.ts | 2 +- test/load-balancer/load-balancer.test.ts | 66 +- test/security/config.test.ts | 4 +- .../security/error-handler-middleware.test.ts | 1 - .../jwt-key-rotation-middleware.test.ts | 234 +- test/security/jwt-key-rotation.test.ts | 304 ++- test/security/session-manager.test.ts | 4 - test/security/tls-integration.test.ts | 4 +- test/security/tls-manager.test.ts | 4 +- test/security/utils.test.ts | 23 +- tsconfig.build.json | 4 +- 47 files changed, 3640 insertions(+), 981 deletions(-) delete mode 100644 examples/cert.pem create mode 100644 sec-findings.md diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index c668b65..6538fb0 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -12,7 +12,7 @@ jobs: bun-version: latest - name: Install dependencies - run: bun install + run: bun install --frozen-lockfile #- name: Linting # run: bun run format diff --git a/.gitignore b/.gitignore index 7b1c024..aab152a 100644 --- a/.gitignore +++ b/.gitignore @@ -145,4 +145,6 @@ results/ .plan.md -sec-findings.md \ No newline at end of file +sec-findings.md*.pem +*.key +examples/cert.* diff --git a/AGENTS.md b/AGENTS.md index c85547f..24b34ae 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -81,6 +81,7 @@ src/ ### Path Validation (input-validator.ts + utils.ts) **Two-pass validation** against double-encoding attacks: + 1. **First pass:** Check raw path against `blockedPatterns` (catches null bytes, `../`) 2. **Recursive decode:** `recursiveDecodeURIComponent()` decodes up to 5 layers until stable 3. **Second pass:** Check fully-decoded path (catches `%252f` → `%2f` → `/`) @@ -90,6 +91,7 @@ Never validate before decoding — attackers hide behind encoding layers. ### Health Checks (http-load-balancer.ts) Threshold-based to prevent flapping and cascade failures: + - `failureThreshold` (default 3): consecutive failures before marking unhealthy - `successThreshold` (default 2): consecutive successes before marking healthy again - `minHealthyTargets` (default 1): floor check — refuses to mark the last healthy target down @@ -105,6 +107,7 @@ secure header priority (`cf-connecting-ip` > `x-real-ip`). ### Error Handling Global error handler registered on the 0http-bun router. In production: + - Returns sanitized `{"error":"Internal server error"}` with status 500 - Never leaks stack traces or internal file paths - Logs full error details internally @@ -112,7 +115,15 @@ Global error handler registered on the 0http-bun router. In production: ### Blocked Patterns (config.ts) ```typescript -blockedPatterns: [/\.\./, /%2e%2e/i, /%2f/i, /%5c/i, /%00/, /\0/, /%25%32%[fF]/i] +blockedPatterns: [ + /\.\./, + /%2e%2e/i, + /%2f/i, + /%5c/i, + /%00/, + /\0/, + /%25%32%[fF]/i, +] ``` Covers: raw `..`, encoded `../`, encoded `/`, encoded `\`, null byte, double-encoded `/`. diff --git a/benchmark/bungate-gateway.ts b/benchmark/bungate-gateway.ts index af1fcec..20460f5 100644 --- a/benchmark/bungate-gateway.ts +++ b/benchmark/bungate-gateway.ts @@ -1,3 +1,11 @@ +/** + * ═══════════════════════════════════════════════════════════════════════════ + * FOR BENCHMARKING ONLY — NOT FOR PRODUCTION + * This file intentionally disables security features to maximize throughput. + * Do not use this configuration as a template for production deployments. + * ═══════════════════════════════════════════════════════════════════════════ + */ + import { BunGateway } from './src' import { BunGateLogger } from './src' import { cpus } from 'os' diff --git a/benchmark/echo-server-simple.ts b/benchmark/echo-server-simple.ts index 897e5c7..08599d2 100644 --- a/benchmark/echo-server-simple.ts +++ b/benchmark/echo-server-simple.ts @@ -1,9 +1,23 @@ +/** + * ═══════════════════════════════════════════════════════════════════════════ + * FOR BENCHMARKING ONLY — NOT FOR PRODUCTION + * ═══════════════════════════════════════════════════════════════════════════ + */ + const serverId = process.env.SERVER_ID || 'unknown' const port = parseInt(process.env.SERVER_PORT || '8080') let requestCount = 0 let startTime = Date.now() +const SENSITIVE_HEADERS = new Set([ + 'authorization', + 'cookie', + 'proxy-authorization', + 'x-api-key', + 'x-metrics-key', +]) + const server = Bun.serve({ port, fetch(req) { @@ -19,7 +33,14 @@ const server = Bun.serve({ }) } - // Echo endpoint with server info + // Echo endpoint with server info — redact sensitive headers + const safeHeaders: Record = {} + for (const [name, value] of req.headers.entries()) { + safeHeaders[name] = SENSITIVE_HEADERS.has(name.toLowerCase()) + ? '[REDACTED]' + : value + } + const response = { server_id: serverId, request_count: requestCount, @@ -27,16 +48,13 @@ const server = Bun.serve({ timestamp: now, method: req.method, url: req.url, - headers: Object.fromEntries(req.headers.entries()), + headers: safeHeaders, remote_addr: req.headers.get('x-forwarded-for') || 'unknown', } return new Response(JSON.stringify(response, null, 2), { headers: { 'Content-Type': 'application/json', - Server: `echo-server-${serverId}`, - 'X-Request-Count': requestCount.toString(), - 'X-Server-Id': serverId, }, }) }, diff --git a/docs/index.html b/docs/index.html index 47d1162..5d256ca 100644 --- a/docs/index.html +++ b/docs/index.html @@ -17,13 +17,22 @@ Bungate — Lightning-Fast HTTP Gateway & Load Balancer - + - - + + @@ -33,374 +42,1100 @@ - - + + - - - - - - - - + + + + + + + + - -
-
- +
+
+ Open Source
- -

- Bungate — Lightning-Fast HTTP Gateway + +

+ Bungate — Lightning-Fast + HTTP Gateway

-

- Enterprise-grade HTTP gateway & load balancer built on Bun. TLS 1.3, JWT key rotation, 8+ load balancing strategies, and zero-config simplicity. +

+ Enterprise-grade HTTP gateway & load balancer built on Bun. TLS 1.3, JWT + key rotation, 8+ load balancing strategies, and zero-config simplicity.

-
- - +
-
18K+
Requests / second
-
<1ms
Routing Overhead
-
8+
LB Strategies
-
TLS 1.3
Enterprise Security
-
98.9%
Test Coverage
+
+
18K+
+
Requests / second
+
+
+
<1ms
+
Routing Overhead
+
+
+
8+
+
LB Strategies
+
+
+
TLS 1.3
+
Enterprise Security
+
+
+
98.9%
+
Test Coverage
+
-
+
-

Built for developers who demand performance

-

A gateway that combines Bun's native speed with enterprise security — no compromises, no config overhead.

- -
-
-
-

Bun-Native Performance

-

Optimized for Bun's runtime. 18K+ req/s, single-digit ms latency, sub-30ms p99 response times in production benchmarks against nginx and envoy.

+

+ Built for developers who demand performance +

+

+ A gateway that combines Bun's native speed with enterprise security — + no compromises, no config overhead. +

+ +
+
+
+ ⚡ +
+

+ Bun-Native Performance +

+

+ Optimized for Bun's runtime. 18K+ req/s, single-digit ms latency, + sub-30ms p99 response times in production benchmarks against nginx + and envoy. +

-
-
🧠
-

Smart Load Balancing

-

Round-robin, least-connections, weighted, ip-hash, random, power-of-two-choices, latency, weighted-least-connections. Cookie-based sticky sessions.

+
+
+ 🧠 +
+

+ Smart Load Balancing +

+

+ Round-robin, least-connections, weighted, ip-hash, random, + power-of-two-choices, latency, weighted-least-connections. + Cookie-based sticky sessions. +

-
-
🔒
-

Enterprise Security

-

TLS 1.3 with auto HTTP redirect, JWT key rotation with JWKS, input validation, CSRF protection, security headers, trusted proxy validation, OWASP Top 10 coverage.

+
+
+ 🔒 +
+

+ Enterprise Security +

+

+ TLS 1.3 with auto HTTP redirect, JWT key rotation with JWKS, input + validation, CSRF protection, security headers, trusted proxy + validation, OWASP Top 10 coverage. +

-
-
-
-

TypeScript First

-

Complete type definitions for every API. IDE autocomplete, type safety, and inline documentation from bun add bungate to production.

+
+
+
+ ⌨ +
+

+ TypeScript First +

+

+ Complete type definitions for every API. IDE autocomplete, type + safety, and inline documentation from + bun add bungate + to production. +

-
-
🔧
-

Production Ready

-

Circuit breakers, health checks with configurable intervals, auto-failover, timeout management, cluster mode with zero-downtime rolling restarts. Built for reliability.

+
+
+ 🔧 +
+

+ Production Ready +

+

+ Circuit breakers, health checks with configurable intervals, + auto-failover, timeout management, cluster mode with zero-downtime + rolling restarts. Built for reliability. +

-
-
🎯
-

Zero Config

-

Works out of the box with sensible defaults. Get started in seconds — production-ready from day one with Prometheus metrics, structured logging, and health endpoints.

+
+
+ 🎯 +
+

+ Zero Config +

+

+ Works out of the box with sensible defaults. Get started in + seconds — production-ready from day one with Prometheus metrics, + structured logging, and health endpoints. +

@@ -411,7 +1146,10 @@

Zero Co

Production-ready in seconds

-

Install, configure, deploy. A complete API gateway with load balancing, auth, and security — from a single file.

+

+ Install, configure, deploy. A complete API gateway with load + balancing, auth, and security — from a single file. +

@@ -420,44 +1158,59 @@

Production-ready in seconds

-
-
-// gateway.ts — production-ready in one file -import { BunGateway } from 'bungate' - -const gateway = new BunGateway({ - server: { port: 3000 }, - cluster: { enabled: true, workers: 4 }, - auth: { secret: process.env.JWT_SECRET }, - metrics: { enabled: true }, -}) - -gateway.addRoute({ - pattern: '/api/*', - loadBalancer: { - strategy: 'least-connections', - targets: [ - { url: 'http://api1.example.com' }, - { url: 'http://api2.example.com' }, - ], - healthCheck: { enabled: true, interval: 15000, path: '/health' }, - }, - circuitBreaker: { enabled: true, failureThreshold: 5 }, -}) - -await gateway.listen() -console.log('🚀 Bungate cluster running on :3000') +
+
+ // gateway.ts — production-ready in one file + import { BunGateway } + from 'bungate' + + const gateway = new + BunGateway({ server: { port: + 3000 }, cluster: { enabled: + true, workers: 4 }, + auth: { secret: process.env.JWT_SECRET }, + metrics: { enabled: true }, }) gateway.addRoute({ pattern: '/api/*', loadBalancer: { + strategy: 'least-connections', targets: [ { + url: 'http://api1.example.com' }, { url: + 'http://api2.example.com' }, ], + healthCheck: { enabled: true, interval: + 15000, path: + '/health' }, }, circuitBreaker: { enabled: + true, failureThreshold: + 5 }, }) + + await gateway.listen() console.log('🚀 Bungate cluster running on :3000')

-
+

Battle-tested security defaults

-

Every request passes through a defense-in-depth pipeline — from TLS termination to JWT validation to input sanitization.

+

+ Every request passes through a defense-in-depth pipeline — from TLS + termination to JWT validation to input sanitization. +

✓ TLS 1.3 @@ -472,136 +1225,378 @@

Battle-tested security defaults

✓ CSRF Protection
-
-
-// TLS 1.3 + JWT key rotation — zero-downtime -const gateway = new BunGateway({ - security: { - tls: { - enabled: true, - cert: './cert.pem', - key: './key.pem', - minVersion: 'TLSv1.3', - cipherSuites: ['TLS_AES_256_GCM_SHA384', 'TLS_CHACHA20_POLY1305_SHA256'], - redirectHTTP: true, - }, - jwtKeyRotation: { - secrets: [ - { key: process.env.JWT_NEW, kid: '2025-05', primary: true }, - { key: process.env.JWT_OLD, kid: '2025-04', deprecated: true }, - ], - jwksUri: 'https://auth.example.com/.well-known/jwks.json', - jwksRefreshInterval: 3600000, - }, - inputValidation: { - maxPathLength: 2048, - maxHeaderSize: 16384, - blockedPatterns: [/\\.\\./, /%00/, /<script>/i], - }, - }, -}) +
+
+ // TLS 1.3 + JWT key rotation — zero-downtime + const gateway = new + BunGateway({ security: { tls: { enabled: + true, cert: + './cert.pem', key: + './key.pem', minVersion: + 'TLSv1.3', cipherSuites: ['TLS_AES_256_GCM_SHA384', 'TLS_CHACHA20_POLY1305_SHA256'], + redirectHTTP: true, }, jwtKeyRotation: { + secrets: [ { key: process.env.JWT_NEW, kid: + '2025-05', primary: + true }, { key: process.env.JWT_OLD, kid: '2025-04', deprecated: + true }, ], jwksUri: + 'https://auth.example.com/.well-known/jwks.json', jwksRefreshInterval: 3600000, }, + inputValidation: { maxPathLength: 2048, + maxHeaderSize: 16384, blockedPatterns: + [/\\.\\./, /%00/, + /<script>/i], }, }, })
-
+
-

Penetration tested. 803 tests. Zero failures.

-

- Bungate underwent a comprehensive security audit in an isolated Docker environment. - Every vulnerability found was fixed and verified before shipping. Here's the real data. +

+ Penetration tested. 803 tests. Zero failures. +

+

+ Bungate underwent a comprehensive security audit in an isolated Docker + environment. Every vulnerability found was fixed and verified before + shipping. Here's the real data.

-
-
-
🛡
-

Pentest Verified

-

- Full security audit with exploit simulation: double-encoding traversal, health check cascade DoS, X-Forwarded-For rate limit bypass, CORS evasion. All 4 vulnerabilities found and fixed. +

+
+
🛡
+

+ Pentest Verified +

+

+ Full security audit with exploit simulation: double-encoding + traversal, health check cascade DoS, X-Forwarded-For rate limit + bypass, CORS evasion. All 4 vulnerabilities + found and fixed.

-
-
-

Zero Regressions

-

- Every security fix validated against the full 803-test suite. 633 to 803 tests during coverage improvement. Zero pre-existing tests broken by security patches. +

+
+

+ Zero Regressions +

+

+ Every security fix validated against the full 803-test suite. + 633 to 803 tests during + coverage improvement. Zero pre-existing tests broken by security + patches.

-
-
🔬
-

Recursive Decode Engine

-

- Custom recursiveDecodeURIComponent() defeats multi-layer encoding attacks (%252f to %2f to /). Two-pass validation: raw path then fully-decoded path. +

+
🔬
+

+ Recursive Decode Engine +

+

+ Custom + recursiveDecodeURIComponent() + defeats multi-layer encoding attacks (%252f to + %2f to /). Two-pass validation: raw path + then fully-decoded path.

-
-
-
-
98.97%
-
Line Coverage
+
+
+
+
+ 98.97% +
+
+ Line Coverage +
-
-
94.55%
-
Function Coverage
+
+
+ 94.55% +
+
+ Function Coverage +
-
-
803
-
Tests (44 files)
+
+
+ 803 +
+
+ Tests (44 files) +
-
-
0
-
Failures
+
+
+ 0 +
+
+ Failures +
-
-
-
- 🔒 - Input Validation - FIXED +
+
+
+ 🔒 + Input Validation + FIXED
-

- Double-encoding (%252f) and quad-dot traversal now defeated by recursive decode + two-pass validation + expanded blocked patterns. +

+ Double-encoding (%252f) and quad-dot traversal now + defeated by recursive decode + two-pass validation + expanded + blocked patterns.

-
-
- - Cascade Failure - FIXED +
+
+ + Cascade Failure + FIXED
-

- Threshold-based health checks: 3 consecutive failures to mark unhealthy, 2 successes to recover. Min-healthy floor prevents complete cascade. +

+ Threshold-based health checks: 3 consecutive failures to mark + unhealthy, 2 successes to recover. Min-healthy floor prevents + complete cascade.

-
-
- 📈 - Rate Limit Bypass - FIXED +
+
+ 📈 + Rate Limit Bypass + FIXED
-

- Rate limiter now keys on the gateway's getClientIP() via trusted proxy validator. X-Forwarded-For rotation no longer bypasses limits. +

+ Rate limiter now keys on the gateway's + getClientIP() via trusted proxy validator. + X-Forwarded-For rotation no longer bypasses limits.

-
-
- 🌐 - Error Handler - FIXED +
+
+ 🌐 + Error Handler + FIXED
-

- Global error handler properly catches exceptions. CORS preflight returns clean 204. No more stack trace or internal file path leakage. +

+ Global error handler properly catches exceptions. CORS preflight + returns clean 204. No more stack trace or internal file path + leakage.

@@ -609,74 +1604,160 @@

Recursive Decode Engine

-
-

Ready to ship faster?

-

Enterprise security, zero config. Install and deploy in minutes.

- - +
+

+ Ready to ship faster? +

+

+ Enterprise security, zero config. Install and deploy in minutes. +

+
+ + + View on GitHub
-