Web Application Firewall (WAF) & OWASP Injection Protection
Overview
Toron includes a native, high-throughput Web Application Firewall (WAF) middleware engine (pkg/waf) designed to intercept and mitigate Layer 7 security threats (OWASP Top 10) before they reach downstream application handlers or backend microservices.
Key Capabilities
- OWASP Top 10 Injection Mitigation:
- SQL Injection (SQLi): Detects
UNION SELECT,' OR 1=1, and destructive DDL statements (DROP TABLE,INSERT INTO). - Cross-Site Scripting (XSS): Intercepts script tags (
<script>), inline event handlers (onerror=,onload=), andjavascript:URIs. - Path Traversal / LFI: Detects directory escape sequences (
../,%2e%2e/) and sensitive system files (/etc/passwd) via raw wire URI evaluation and layered route-aware defense (see Path Traversal Defense). - Command Injection / RCE: Intercepts shell command chaining (
; /bin/sh,| bash) and PHP/system execution primitives (eval(),system()).
- SQL Injection (SQLi): Detects
- Flexible Evaluation Modes:
enforce: Immediately blocks malicious requests with HTTP403 Forbiddenand a structured JSON error response.detection: Passes requests through to application handlers while logging anomaly threat scores and attachingX-Toron-WAF-Anomaly-Scoreheaders.
- Protocol Integrity & HTTP Request Smuggling Guard:
- Request Smuggling Prevention: Rejects requests containing both
Content-LengthandTransfer-Encodingheaders or mismatched duplicateContent-Lengthheader values with400 Bad Request. - Control Character Filtering: Rejects non-printable ASCII control characters (
0x00–0x1F,0x7F) in paths, query parameters, or header fields. - Payload Size Limits: Enforces strict byte limits on single header values (4 KB), query strings (4 KB), and parameters (2 KB) returning
413 Payload Too Large.
- Request Smuggling Prevention: Rejects requests containing both
- CIDR-Based IP Access Control Lists (ACLs) & Anti-Spoofing:
- Allowed IPs (
allowed_ips): Configurable list of IPv4 and IPv6 CIDR blocks (e.g.10.0.0.0/8,192.168.1.0/24) or single IP addresses. When configured, requests originating from client IPs outside these ranges shall be immediately rejected with HTTP403 Forbidden. - Denied IPs (
denied_ips): Configurable list of IPv4 and IPv6 CIDR blocks (e.g.198.51.100.0/24) or single IP addresses returning403 Forbidden. - Physical RemoteAddr Prioritization: Client IP identity is anchored to the physical network connection address (
req.RemoteIP(),req.RemoteAddr) across HTTP/1.1, HTTP/2, and HTTP/3 QUIC (SEC-31,REQ-092,ADR-087). - Trusted Proxy Gating (
trusted_proxies): Client-suppliedX-Forwarded-ForandX-Real-IPheaders are discarded unless the client’s physical socket IP is verified against configuredtrusted_proxies. Attackers cannot bypass IP blocks or evade allowlists by forging forwarded headers. - Fail-Closed Allowlist Enforcement: When
allowed_ipsis active, any request whose client IP cannot be determined or is malformed is rejected fail-closed with HTTP403 Forbiddenand exact JSON payload{"error":"Forbidden","message":"client IP could not be determined and allowed IP list is enforced"}(SEC-32,REQ-093,ADR-088). - Denylist-Only Fail-Open Pass-Through: When only
denied_ipsis configured without an active allowlist, unidentifiable client IPs pass through the IP ACL stage (fail-open) to subsequent WAF stages and downstream handlers (REQ-093). - Single-Pass Hot-Path IP Extraction: Client IP resolution via
ExtractClientIPexecutes exactly once at the entry of the middleware closure, caching parsednet.IPfor unconditional access evaluation and structured telemetry. - Fast-Path $O(1)$ Pre-Inspection: IP access checking executes before deep regex scanning or body buffering.
- Allowed IPs (
- Per-Route WAF Customization & Overrides (
routes.yaml):- Any individual route in
routes.yamlcan define its ownwaf:block to selectively override global settings (e.g. tuning anomaly thresholds, disabling specific rules likeSQLI-001for legacy backends, or setting dedicated CIDR allowlists).
- Any individual route in
- Multi-Location & Bounded Inspection:
- Scans URL paths, raw query strings, HTTP headers, and request body payloads up to a configurable maximum size (
max_inspect_body_size), preserving payload streams for downstream handlers.
- Scans URL paths, raw query strings, HTTP headers, and request body payloads up to a configurable maximum size (
Configuration in config.yaml
server:
# Web Application Firewall (WAF) & Layer 7 OWASP Injection Protection Engine
waf:
enabled: true # Enable WAF Layer 7 threat inspection middleware
mode: "enforce" # Evaluation mode: "enforce" (403 block) or "detection" (log-only score)
anomaly_threshold: 5 # Threat score limit above which request is blocked
max_inspect_body_size: 65536 # Maximum payload body bytes scanned (64 KB)
disabled_rules: [] # Optional list of rule IDs to bypass (e.g. ["SQLI-002"])
allowed_ips: # Optional global CIDR IP allowlist
- "10.0.0.0/8"
- "127.0.0.1"
denied_ips: # Optional global CIDR IP denylist
- "198.51.100.0/24"
trusted_proxies: # Optional CIDR subnets allowed to supply forwarded client IPs
- "10.0.0.1/32"
Route-Level WAF Overrides in routes.yaml
routes:
# 1. Admin route with strict CIDR IP access control & trusted proxy delegation
- type: "upstream"
prefix: "/services/secure-admin"
target: "http://localhost:9001"
waf:
enabled: true
mode: "enforce"
allowed_ips:
- "10.0.0.0/8"
- "127.0.0.1"
denied_ips:
- "10.99.0.0/16"
trusted_proxies:
- "10.0.0.1/32"
# 2. Legacy API route with SQLI-001 rule disabled
- type: "upstream"
prefix: "/services/legacy-api"
target: "http://localhost:9002"
waf:
enabled: true
mode: "enforce"
disabled_rules:
- "SQLI-001"
Fail-Closed IP Access Control on Unidentifiable Client IP (SEC-32, REQ-093)
Security Problem & Vulnerability Remediation
In earlier releases, when an IP allowlist (allowed_ips) was enforced, incoming requests lacking resolvable client IP metadata (e.g., stripped connection addresses, intermediate proxy header drops, synthetic test requests, or malformed non-IP headers) bypassed access control checks because the middleware guarded evaluation with if ip != nil and CheckIP(nil) defaulted to fail-open (true, ""). This critical vulnerability was tracked as SEC-32 (CWE-284, CWE-1188, CWE-693, SR-091 Finding 2).
Toron v1.5.13 remediates this vulnerability under REQ-093 and ADR-088 by enforcing fail-closed access control on allowlists, context-aware policy evaluation, and single-pass client IP extraction.
Behavior Under Active Allowlist (allowed_ips Enforced — Fail-Closed)
When an IP allowlist (allowed_ips or allowedSubnets) is configured and active globally in config.yaml or on a specific route in routes.yaml:
- Strict Positive Security Invariant: Any request whose client IP cannot be verified against the configured allowlist is immediately rejected fail-closed.
- Evaluation Invariant: If client IP extraction yields
nil(due to missingRemoteAddr, unverified forwarded headers behind untrusted proxies, or malformed/unparseable values like"unknown","localhost","999.999.999.999",":::invalid"),IPAccessList.CheckIP(nil)returnsallowed: falsewith reason"client IP could not be determined and allowed IP list is enforced". - HTTP 403 Forbidden Response:
- Status code:
403 Forbidden - Header:
Content-Type: application/json - Exact Body:
{"error":"Forbidden","message":"client IP could not be determined and allowed IP list is enforced"}
- Status code:
- Immediate Execution Termination: Middleware immediately halts request processing without calling
next(req, res)or forwarding traffic to upstream services. - Observability & Audit Trail:
- Increments Prometheus counter
toron_waf_blocked_requests_total{category="ip_acl", route="..."}. - Emits a structured
SecurityEventto the WAF audit logger withEvent: "ip_acl_block",Action: "blocked",Category: "ip_acl",Location: "remote_addr", andClientIP: ""(empty string, safe from null-pointer dereference panics).
- Increments Prometheus counter
Behavior Under Denylist-Only Configurations (denied_ips Configured — Fail-Open Pass-Through)
When only denied_ips is configured without an active allowed_ips allowlist:
- Negative Security Model: Denylists are exclusionary filters designed to block known malicious actors while allowing all other legitimate traffic.
- Fail-Open Pass-Through: If the incoming client IP cannot be determined (
ExtractClientIPreturnsnil),IPAccessList.CheckIP(nil)returnsallowed: true, reason: "". - Subsequent Stage Inspection: The request passes through the IP ACL stage and proceeds to subsequent WAF inspection layers (Protocol Integrity, Custom Rules, OWASP Injection Rules) and downstream routing.
- Operational Availability: Preserves availability for internal service mesh calls, synthetic health probes, or intermediate proxies that do not provide client IP headers, eliminating false-positive outages.
Single-Pass Client IP Extraction Optimization
To eliminate redundant CPU overhead and minimize request latency on the hot path:
- Single Extraction per Request: In
pkg/waf/middleware.go,ExtractClientIP(req, tp)is executed exactly once at the entry of the WAF middleware closure:clientNetIP := ExtractClientIP(req, tp) clientIP := "" if clientNetIP != nil { clientIP = clientNetIP.String() } - Unconditional ACL Evaluation: The cached
clientNetIP net.IPis passed directly toacl.CheckIP(clientNetIP)wheneveracl != nil && acl.HasRules()evaluates totrue, removing the vulnerableif ip != nilguard. - Telemetry & Audit Parity: The string representation
clientIPis computed once and reused across all subsequent security telemetry:- IP ACL denial events (
ip_acl_block) - Protocol integrity violation events (
protocol_violation) - Custom rules and OWASP injection rule evaluation and audit logging
- IP ACL denial events (
- Zero-Allocation Hot Path: Eliminates duplicate socket host/port parsing, repeated CIDR lookups against
trusted_proxies, and unnecessary heap allocations on benign requests.
Policy Evaluation Matrix
| Client IP State | Allowlist (allowed_ips) |
Denylist (denied_ips) |
WAF IP ACL Verdict | HTTP Status | Response Payload | Next WAF Stages Executed? |
|---|---|---|---|---|---|---|
| Unidentifiable / Nil / Malformed | Active | Any | Blocked (Fail-Closed) | 403 |
{"error":"Forbidden","message":"client IP could not be determined and allowed IP list is enforced"} |
No (Immediate Halt) |
| Unidentifiable / Nil / Malformed | None | Active | Allowed (Fail-Open) | N/A | N/A (Pass-Through) | Yes |
| Identified (Valid IP) | Matches Allowed CIDR | Does Not Match Denied | Allowed | N/A | N/A (Pass-Through) | Yes |
| Identified (Valid IP) | Outside Allowed CIDR | Any | Blocked | 403 |
{"error":"Forbidden","message":"IP address is not in the allowed IP list"} |
No (Immediate Halt) |
| Identified (Valid IP) | Any | Matches Denied CIDR | Blocked | 403 |
{"error":"Forbidden","message":"IP address matches denied IP list"} |
No (Immediate Halt) |
Architecture & Evaluation Flow
flowchart TD
Req["Incoming Request at WAF Middleware"] --> SinglePass["Single-Pass Extraction:\nclientNetIP := ExtractClientIP(req, tp)\nclientIP := clientNetIP.String() (or '')"]
SinglePass --> CheckRules{"acl != nil &&\nacl.HasRules()?"}
CheckRules -- "No" --> Pass["Proceed to Protocol Integrity\n& OWASP Injection Inspection"]
CheckRules -- "Yes" --> UnconditionalCheck["Invoke acl.CheckIP(clientNetIP)\n(Unconditional Evaluation)"]
UnconditionalCheck --> CheckNil{"clientNetIP == nil?"}
CheckNil -- "Yes (ip == nil)" --> AllowlistActive{"Allowlist Configured?\n(allowed_ips active)"}
AllowlistActive -- "Yes" --> FailClosed["Fail-Closed Denial:\nStatus 403 Forbidden\n'client IP could not be determined...'"]
AllowlistActive -- "No (Denylist only)" --> Pass
CheckNil -- "No (Valid IP)" --> CheckDeny{"Matches Denylist?"}
CheckDeny -- "Yes" --> DenyBlock["Fail-Closed Denial:\nStatus 403 Forbidden\n'IP address matches denied...'"]
CheckDeny -- "No" --> CheckAllow{"Allowlist Configured?"}
CheckAllow -- "No (Denylist only)" --> Pass
CheckAllow -- "Yes" --> MatchAllow{"Matches Allowlist?"}
MatchAllow -- "Yes" --> Pass
MatchAllow -- "No" --> WhitelistBlock["Fail-Closed Denial:\nStatus 403 Forbidden\n'IP address is not in allowed...'"]
subgraph RejectionHandler["WAF Denial Processing"]
FailClosed --> RecordMetrics["Increment toron_waf_blocked_requests_total{category='ip_acl'}"]
DenyBlock --> RecordMetrics
WhitelistBlock --> RecordMetrics
RecordMetrics --> EmitAudit["Emit Structured Audit Event (ip_acl_block)"]
EmitAudit --> WriteResponse["Write HTTP 403 JSON Response & Terminate (No next)"]
end
Triggered Block Response Format
When a request is blocked in enforce mode, Toron returns 403 Forbidden with an application/json payload depending on the violation:
1. OWASP Top 10 Injection Violations
{
"error": "Forbidden",
"message": "WAF security violation detected",
"threat_score": 5,
"triggered_rules": ["SQLI-001"]
}
2. Fail-Closed Unidentifiable Client IP (Allowlist Enforced - SEC-32)
{
"error": "Forbidden",
"message": "client IP could not be determined and allowed IP list is enforced"
}
3. IP Access Control List Violations (Identified IP)
- Denied IP Address:
{ "error": "Forbidden", "message": "IP address matches denied IP list" } - Disallowed IP Address:
{ "error": "Forbidden", "message": "IP address is not in the allowed IP list" }
Prometheus Observability & Metrics
Toron exports real-time WAF telemetry at the standard /metrics endpoint:
toron_waf_blocked_requests_total{category="sqli|xss|traversal|rce|protocol|ip_acl", route="/..."}: Total number of blocked requests categorized by threat vector and route.toron_waf_anomalies_detected_total{category="...", mode="detection"}: Total threat anomalies detected in detection mode.toron_waf_inspection_duration_seconds: Histogram tracking WAF inspection execution latency.
# Example Prometheus Alert Query for SQLi spikes:
sum(rate(toron_waf_blocked_requests_total{category="sqli"}[5m])) > 10
Structured Security Audit Logging
Toron emits structured, SIEM-ready JSON log lines for all security violations to stdout, stderr, or a dedicated log file:
{
"timestamp": "2026-08-15T14:30:00Z",
"event": "waf_block",
"client_ip": "198.51.100.45",
"method": "POST",
"path": "/api/users",
"category": "sqli",
"rule_id": "SQLI-001",
"anomaly_score": 5,
"action": "blocked",
"location": "query",
"payload_snippet": "1 UNION SELECT username, password FROM users"
}
Web Control Center Security Dashboard & Real-Time Incidents Feed
Toron’s Web Control Center served at /internal/dashboard/ includes a dedicated Security & WAF Dashboard:
- Security & WAF Overview Tab:
- Live indicators for WAF Engine Mode (
ENFORCE/DETECTION), Intercepted Threat Count, Active Inspection Rules count, and CIDR IP Access Lists. - Security Policy Matrix: Visual verification of active WAF rulesets, CIDR subnets, Enterprise Security Headers, CORS, and Mutual TLS policies.
- Live indicators for WAF Engine Mode (
- Real-Time Security Audit Stream:
- Live incident feed table displaying intercepted security threats in real-time.
- Categorized threat badges (
SQLi,XSS,Traversal,RCE,IP ACL,Protocol), client IP, triggered rule ID, HTTP method & path, threat score, and action taken (BLOCKED/LOGGED). - Powered by the
/internal/api/security/incidentsmanagement endpoint.
- Interactive WAF Attack Presets:
- The Live API Tester composer includes pre-configured WAF attack payloads (SQL Injection, Path Traversal, Command Injection, XSS header) allowing administrators to validate WAF threat interception right from the web dashboard.