Synapse WAF PoC
A proof-of-concept integrating the real Synapse WAF detection engine (237 production rules) with Cloudflare's Pingora proxy framework. Pure Rust, no Node.js, no FFI boundary.
Performance Headlines
| Metric | Result |
|---|---|
| Clean GET | ~10 μs |
| Attack detection | ~25 μs avg across all vectors |
| Full pipeline (WAF + DLP, 4 KB) | ~247 μs |
| Rules loaded | 237 production rules |
| Benchmark suites | 19 suites, 306 benchmarks |
| vs NAPI (Node.js FFI) | ~2-3x faster |
| vs ModSecurity | 4-19x faster |
Note: February 2026 Criterion.rs numbers on macOS arm64. See
docs/performance/BENCHMARK_REPORT_2026_02.mdfor the full report.
Architecture
Pingora Approach (This PoC)
flowchart LR
Client -->|request| SP["Synapse WAF<br/><b>Single Binary</b>"]
SP -->|proxy| Backend[Backend Server]
Backend -->|response| SP
SP -->|response| Client
subgraph SP_inner [" "]
direction TB
Engine["libsynapse (in-proc)<br/>237 Rules · Entity Tracking · Risk Scoring"]
end
style SP fill:#1e40af,color:#fff
style Engine fill:#2563eb,color:#fff
style Client fill:#f8fafc,stroke:#334155
style Backend fill:#f8fafc,stroke:#334155
Current Approach (nginx + Node.js)
flowchart LR
Client -->|request| Nginx[nginx]
Nginx -->|subrequest| RS["risk-server<br/>(Node.js)"]
RS -->|verdict| Nginx
Nginx -->|proxy| Backend[Backend Server]
RS --- NAPI["NAPI Bridge"]
NAPI --- Lib["libsynapse<br/>(Rust FFI)"]
style Nginx fill:#dc2626,color:#fff
style RS fill:#dc2626,color:#fff
style NAPI fill:#b91c1c,color:#fff
style Lib fill:#991b1b,color:#fff
style Client fill:#f8fafc,stroke:#334155
style Backend fill:#f8fafc,stroke:#334155
3 components + FFI overhead vs a single Rust binary.
Key difference: Detection happens inside the proxy, not across a process boundary.
Quick Start
# Build release binary
# Run (uses default config)
# Run with interactive TUI dashboard
# Or with config file
# Run integration tests
Benchmark Results (February 2026)
Criterion.rs results from 19 benchmark suites (306 benchmarks), release build with LTO:
Detection Engine
| Benchmark | Latency | Notes |
|---|---|---|
| Simple GET | 10.0 μs | Minimal GET, no params |
| SQLi detection | 26.6 μs | Average across 5 SQLi variants |
| XSS detection | 23.3 μs | Average across 3 XSS variants |
| Evasive attacks | 25-33 μs | Hex, double-encoding, unicode, polyglot |
| Full rule set (237) | 71.6 μs | Linear scaling, ~302 ns/rule |
Per-Request Hot Path
| Operation | Latency |
|---|---|
| Rate limit check | 61 ns |
| ACL evaluation (100 rules) | 156 ns |
| Trap matching (honeypot) | 33 ns |
| Actor is-blocked check | 45 ns |
| Session validation | 304 ns |
End-to-End Pipeline
| Scenario | Latency |
|---|---|
| Clean GET, full chain | 72 μs |
| WAF + DLP (4 KB body) | 247 μs |
| WAF + DLP (8 KB body) | 442 μs |
| E-commerce order (heavy) | 1.6 ms |
| Healthcare claim (PII + DLP) | 2.3 ms |
Comparison
| Implementation | Detection Latency | Notes |
|---|---|---|
| Synapse WAF | ~10-25 μs | Pure Rust, no FFI boundary |
| libsynapse (NAPI) | ~62-73 μs | Node.js + Rust FFI overhead |
| ModSecurity | 100-500 μs | Depends on ruleset |
| AWS WAF | 50-200 μs | Cloud service |
Value Proposition
Pingora eliminates the ~47 μs FFI overhead (73 μs NAPI vs 25 μs pure Rust), providing a ~2-3x speedup over the Node.js architecture:
- Simpler architecture - Single Rust binary vs nginx + Node.js + NAPI stack
- No serialization boundary - Detection runs in-process, no IPC
- No GC pauses - No V8 heap, predictable latency
- Graceful reload - Zero-downtime updates via SIGQUIT + socket handoff
- Thread-local engines - Each Pingora worker has its own Synapse instance
| Metric | Current (nginx + NAPI) | Pingora | Improvement |
|---|---|---|---|
| Per-request latency | ~73 μs | ~25 μs | ~3x faster |
| Components to deploy | 3 (nginx, Node.js, NAPI) | 1 binary | Simpler |
| Memory footprint | Node.js + V8 heap | Rust only | ~50% smaller |
| Cold start | Seconds (V8 init) | Milliseconds | Much faster |
| Config reload | Service restart | 240 μs hot reload | Zero downtime |
Configuration
Copy config.example.yaml to config.yaml:
# Server settings (flat fields on GlobalConfig)
http_addr: "0.0.0.0:80"
https_addr: "0.0.0.0:443"
workers: 0 # 0 = auto-detect CPU count
shutdown_timeout_secs: 30
waf_threshold: 70 # Global risk threshold (0-100)
waf_enabled: true
log_level: "info" # trace, debug, info, warn, error
waf_regex_timeout_ms: 100 # ReDoS protection (max 500)
# admin_api_key: "..." # Optional; random key generated if unset
# Upstream backends (round-robin)
upstreams:
- host: "127.0.0.1"
port: 8080
# Rate limiting
rate_limit:
rps: 10000
enabled: true
# Detection toggles
detection:
sqli: true
xss: true
path_traversal: true
command_injection: true
action: "block" # block, log, challenge
block_status: 403
See docs/reference/configuration.md for the full reference.
Pingora Hooks Used
| Hook | Purpose |
|---|---|
early_request_filter |
Rate limiting (pre-TLS) |
request_filter |
Attack detection (main filter) |
request_body_filter |
DLP body inspection (PII/sensitive data scanning) |
upstream_peer |
Round-robin backend selection |
upstream_request_filter |
Add X-Synapse-* headers |
logging |
Access logs with timing |
Integration Tests
Run the test script to verify everything works:
# With proxy already running
# Or start proxy, run tests, stop proxy
Sample output:
============================================
Synapse WAF Integration Tests
============================================
[INFO] Testing clean requests (should PASS)...
[PASS] Simple GET / (502 - allowed)
[PASS] API endpoint (502 - allowed)
...
[INFO] Testing SQL injection (should BLOCK)...
[PASS] SQLi: OR condition (403) - 2ms
[PASS] SQLi: UNION SELECT (403) - 1ms
...
============================================
Results: 23/23 passed
============================================
All tests passed!
Configuration Hot-Reload
Synapse supports zero-downtime configuration updates via the admin API:
# Reload configuration (~240 μs atomic swap, no dropped requests)
How it works:
- New config is parsed and validated
- Routing table and WAF rules are rebuilt
- Atomic
RwLockswap replaces the live config - In-flight requests continue unaffected
Graceful Shutdown
The process handles SIGQUIT, SIGTERM, and SIGINT for graceful shutdown:
- Signal received — stop accepting new connections
- In-flight requests are allowed to complete (draining)
- Process exits when all connections are closed
Building
# Development build
# Release build (optimized)
# With full optimizations (LTO + native CPU)
RUSTFLAGS="-C target-cpu=native"
# Run tests
# Run benchmarks
Example Usage
Clean Request (Allowed)
# → Proxied to backend
# → X-Synapse-Analyzed: true
# → X-Synapse-Detection-Time-Us: 1
SQL Injection (Blocked)
# → HTTP 403 Forbidden
# → {"error": "blocked", "reason": "sqli"}
XSS (Blocked)
# → HTTP 403 Forbidden
# → {"error": "blocked", "reason": "xss"}
POST with Body
# Body size logged: "Request body complete: 15 bytes"
Upstream Headers
The proxy adds these headers to upstream requests:
| Header | Description |
|---|---|
X-Synapse-Analyzed |
Always "true" |
X-Synapse-Detection-Time-Us |
Detection time in microseconds |
X-Synapse-Client-IP |
Client IP (from X-Forwarded-For or connection) |
Detection Engine
This PoC uses the real libsynapse engine from ../risk-server/libsynapse/, which includes:
- 237 production rules covering SQLi, XSS, path traversal, command injection, and more
- Behavioral tracking - Entity risk accumulates across requests from the same IP
- Risk scoring - Graduated risk levels (0-100) with configurable blocking thresholds
- Rule chaining - Multiple rules can match and contribute to overall risk
Verified Detections
Tested and verified to block:
UNION SELECTSQLi attacks (rule 200200)- Path traversal attempts (rules 200014, 200016)
- Various other attack patterns from the production rule set
Rules Loading
Rules are loaded at startup from (in order of preference):
../risk-server/libsynapse/rules.json(production rules)rules.json(local override)/etc/synapse-pingora/rules.json(system-wide)src/minimal_rules.json(fallback with 7 basic patterns)
Performance Optimizations
- Thread-local engines: Each Pingora worker has its own Synapse instance
- Lazy rule loading: Rules parsed once at startup via
once_cell::Lazy - Zero-copy headers: Header references passed directly to engine
- LTO: Link-time optimization in release builds (profile: fat LTO, 1 codegen unit)
- Native CPU: Build with
RUSTFLAGS="-C target-cpu=native"for best performance
DLP Body Inspection Optimizations
The DLP scanner has been optimized for high-throughput request body scanning:
| Optimization | Description | Impact |
|---|---|---|
| Content-Type Short Circuit | Skip binary types (image/, video/, multipart/form-data) | Eliminates scan overhead for file uploads |
| Inspection Depth Cap | Truncate body to first 8KB by default | O(1) scan time for large payloads |
| Aho-Corasick Prefilter | Single-pass multi-pattern detection | 30-50% faster than sequential regex |
DLP Performance Benchmarks (February 2026)
| Payload Size | With PII | Clean Traffic | Notes |
|---|---|---|---|
| 4 KB | ~34 μs | ~21 μs | E-commerce order payloads |
| 8 KB | ~65 μs | ~42 μs | At inspection cap limit |
| 18 KB | ~68 μs | ~42 μs | Truncated to 8KB cap |
| 32 KB | ~64 μs | ~41 μs | Plateaus due to truncation |
DLP fast mode saves 30-34%: 4 KB drops from ~34 μs to ~24 μs, 8 KB from ~70 μs to ~46 μs.
DLP Configuration Options
// In code (DlpConfig)
DlpConfig
Tuning Recommendations:
- High-security environments: Set
max_body_inspection_bytesto 32KB+ for deeper inspection - High-throughput APIs: Keep default 8KB cap for sub-100μs scan times
- File upload endpoints: Binary content types are automatically skipped
Content Types Automatically Skipped
image/*- All image formatsaudio/*- All audio formatsvideo/*- All video formatsapplication/octet-stream- Binary datamultipart/form-data- File uploadsapplication/zip,application/gzip, etc. - Archivesfont/*- Font filesmodel/*- 3D models
Future Work (For Feature Parity with nginx)
Core Features (Required for Production)
- Full detection rule parity with libsynapse (DONE - using real engine)
- Multi-site/vhost support - Hostname-based routing with per-site config
- TLS termination - SSL certificates, SNI support
- Health check endpoint -
/_sensor/statusequivalent - Per-site WAF config - Override rules, thresholds per hostname
Management Features (Important)
- Metrics endpoint - Prometheus-compatible
/metrics - Config hot-reload API - Update config without restart
- Access lists - Allow/deny CIDRs per site
- Per-site rate limiting - Hostname-aware rate limits
- Signal Horizon telemetry integration
Advanced Features
- DLP scanning in
request_body_filter(DONE - with performance optimizations) - Request body inspection (POST/PUT payloads) (DONE - with truncation cap)
- Custom block pages per site
- Dashboard UI integration (Dashboard compatibility routes)
- Production hardening (security audit remediations complete)
Files
synapse-pingora/
├── Cargo.toml # Dependencies
├── config.example.yaml # Example configuration
├── test.sh # Integration test script
├── README.md
├── benches/
│ └── detection.rs # Criterion benchmarks
├── assets/
│ └── admin_console.html # Embedded admin web console
├── docs/ # Project documentation
│ ├── reference/ # Configuration reference
│ ├── tutorials/ # Tuning, DLP, shadow mirroring
│ └── api/ # Admin API reference
└── src/
├── main.rs # Binary entrypoint + Pingora proxy impl
├── lib.rs # Library crate root
├── config.rs # YAML config loading & validation
├── admin_server.rs # Admin HTTP API (90+ endpoints)
├── api.rs # API handler traits
├── metrics.rs # Prometheus metrics registry
├── health.rs # Health check logic
├── rules.rs # Rule loading & management
├── tui.rs # Interactive terminal dashboard
├── waf/ # WAF detection engine
├── entity/ # IP/actor entity store & risk tracking
├── actor/ # Behavioral actor tracking
├── session/ # Session tracking & hijack detection
├── detection/ # Credential stuffing & login detection
├── correlation/ # Campaign correlation engine
├── intelligence/ # Signal intelligence manager
├── dlp/ # Data Loss Prevention scanner
├── profiler/ # Endpoint profiling & schema learning
├── payload/ # Bandwidth & payload analysis
├── trends/ # Trend analysis & anomaly detection
├── fingerprint/ # JA4 fingerprinting & integrity
├── crawler/ # Bot & crawler detection
├── geo/ # GeoIP & impossible travel detection
├── shadow/ # Shadow traffic mirroring
├── signals/ # Signal adapter layer
├── horizon/ # Signal Horizon hub integration
├── tunnel/ # Secure tunnel client
├── telemetry/ # Telemetry & reporting
├── interrogator/ # CAPTCHA, JS challenge, cookie mgmt
├── persistence/ # State persistence layer
├── tarpit/ # Tarpit (not shown: src/tarpit/)
├── utils/ # Circuit breaker & shared utilities
└── (14 more modules) # access, block_log, block_page, body,
# config_manager, headers, ratelimit,
# reload, shutdown, site_waf, sni_validation,
# tls, trap, validation, vhost
License
Licensed under the GNU Affero General Public License v3.0 only. Copyright Nicholas Crew Ferguson See LICENSE.