WSLProxy WAF Engine v2: Enterprise Enforcement You Can Explain
Stable signature IDs, monitor/block bindings, and support IDs on every decision
Workstation WSL Proxy ships WAF Engine v2 as an explainable enforcement layer on the OpenResty hot path — not a regex snippet nobody owns. Stable signature IDs, monitor/block bindings, and a support ID on every decision. Deep dive: Inside WAF Engine v2. Product: wslproxy.org/waf · Overview: /wsl-proxy.
Watch: WSL Proxy WAF tour
Watch: youtu.be/r10XSonA5JE · Product: wslproxy.org · WAF: wslproxy.org/waf
Opaque edge security vs explainable enforcement
Platform and security teams still inherit three failure modes at the edge. First: a static nginx snippet or ModSecurity pack that nobody owns, so every change is a POP-wide reload argument. Second: a cloud checkbox that blocks traffic without naming the winning rule, binding, or stage. Third: a “monitor mode” that is really just a different product with no path to promote the same policy to block per route.
When something breaks, the ticket says “403 from the edge.” There is no policy ID, no support ID, and no way to stage a noisy signature without rewriting the pack. That is not enterprise enforcement — it is folklore with a status code.
Workstation WSL Proxy treats the edge as a product. Day-to-day routing and WAF policy move on the live-config hot path; nginx reloads stay reserved for listen and SSL. Engine v2 is the security half of that story: a production WAF you can bind per domain and route, run in blocking or transparent mode, govern by stable signature IDs, and operate with structured logs plus correlation IDs.
What Engine v2 is (MVP, shipped)
Engine v2 runs in the OpenResty request path in three Lua modules: api/waf_engine.lua, api/waf_stages.lua, and api/waf_support.lua. It is the design reference for architecture, policy schema, binding precedence, signature governance, observability, and the roadmap that maps remaining App Protect–style features to Phase 2 and Phase 3 — clearly labelled future.
The goal is specific: a WAF that platform and security teams can bind, explain, and roll out safely — not a regex list pasted into a location block. On Workstation’s site we call the product Workstation WSL Proxy; on the product surface it is WSLProxy at wslproxy.org.
If you already read the broader WAF overview (WSL Proxy WAF blog), this piece focuses on Engine v2 itself: constraints, pipeline, operator levers, and where the roadmap stops being “done today.”
Four design constraints in plain language
| Constraint | Meaning for operators |
|---|---|
| In the NGINX path | LuaJIT, compiled-regex cache (o flag), shared dicts for velocity. No blocking I/O on the hot path. |
| Fail-open by default | Engine or stage errors log and allow. A WAF bug must not take the site down. Fail-closed body parse is roadmap Phase 2 — not the default. |
| Backward compatible | v1 policies (waf_rules + mode) keep working; every v2 field is optional and additive. |
| Explainable | Every block names policy, winning binding, stage, violation code, signature ID, and support ID. |
Those four constraints are why Engine v2 feels different from a bolted-on rule file. Availability bias is intentional. Compatibility means you can adopt v2 fields without rewriting every host. Explainability is not a marketing adjective — it is what lands in response headers and wafsec logs.
The pipeline in sixty seconds
A request hits a POP. gateway_ack selects the route. gateway_pipeline runs rate-limit, then WAF, then the rest of the response path. Inside waf_engine.inspect (fail-open wrapper):
- Load policy (30s TTL cache).
- Resolve effective mode and winning binding.
- Run the eight-stage pipeline (pure functions: each returns a finding or nil).
- Run governed signature matching and anomaly threshold.
- On block: 403 plus
X-WAF-Block,X-WAF-Rule,X-WAF-Violation,X-Support-ID, and the block page.
Stages do not decide block versus alarm. The engine does, from the effective enforcement mode, so the same rule set can behave differently per binding without duplication. Stages cover method allow-list, filetype deny, HTTP smuggling/desync, IP and geo, JWT algorithm policy, JSON depth/size, brute-force velocity, and OpenAPI path+method positive security. Signatures then match with disable / stage / set governance and optional anomaly scoring.
gateway_ack → gateway_pipeline (rate-limit → WAF → …)
→ waf_engine.inspect
→ load policy → resolve binding
→ STAGE PIPELINE (8) → SIGNATURES + anomaly
→ block: 403 + X-WAF-* + X-Support-ID
For the annotated schema, binding algorithm, and full violation catalogue, see the long technical article.
Why operators care: binding, staging, support IDs
Binding precedence is most-specific-wins: route override beats per-server waf_mode_override, which beats policy enforcementMode. Longest path prefix wins, so /api/admin beats /api. Every finding records binding — domain, server, or route:<path> — so logs answer which lever won. Today service is a logical label in logs; a service→policy selection map is Phase 2 (future).
Signature governance gives three independent controls: disable by ID (skip entirely), stage until a timestamp (alarm only; does not contribute to anomaly score), and set toggles (block:false downgrades a whole set to alarm-only). That is the safe rollout path: soak noisy signatures without risking an indirect block via the anomaly threshold.
Support IDs use the form WSL-<epoch>-<rand>, echoed as X-Support-ID and rendered into the block page. Structured wafsec JSON lines, the waf_events shared dict / recent-events API, and Prometheus counters (waf_blocked, waf_monitored, waf_inspections, waf_latency, waf_errors) give SRE and security the same correlation story.
Practically: bind a payments policy in blocking on /api/pay, leave /preview transparent, stage a new open-redirect signature until Friday, and when a customer pastes a support ID into a ticket you look it up — you do not guess which anonymous rule fired on another system.
That workflow is what “enterprise enforcement you can explain” means on Workstation WSL Proxy. Security and platform teams share one audit surface with routing and rate limits. Agents and humans can inspect the same policy objects through Admin UI, REST, MCP, or CLI without waiting for a POP-wide nginx reload for ordinary WAF changes.
Roadmap (labelled future — do not blur with MVP)
MVP is done today: domain and route bind, signature sets and per-ID disable/stage, method and filetype, IP and geo, JWT alg, JSON profile, brute-force, OpenAPI path+method, smuggling stage plus signature, structured logs and support IDs, Prometheus, block page, golden tests, CI validation, and Admin UI for WafPolicies/WafRules. Phase 2 (future) includes the service→policy map, deeper OpenAPI param/type checks, XML and GraphQL profiles, cookie integrity, JWT JWKS, Data Guard, references in events, fail-closed parse option, bot/JA3 signals, threat packs, and an aegisctl-style CLI. Phase 3 (future) covers behavioural L7 DoS, IP reputation, MaxMind geo, gRPC/protobuf, Ingress CRDs, and Hyperscan/Vectorscan. Non-goals for v1 remain full RASP, proprietary signature DB clones, and in-path ML training.
Where to go next
- Watch the tour above, then open wslproxy.org/waf.
- Read Inside Workstation WSL Proxy WAF Engine v2 for stages, schema excerpts, binding pseudocode, and the full violation table.
- Skim the product overview at /wsl-proxy and the earlier WAF narrative at WSL Proxy WAF.
- Engine design reference in source (until a dedicated docs site exists): docs/WAF_ENGINE_V2.md on GitHub.
Docs website deferred — this blog and the companion article point at GitHub docs/WAF_ENGINE_V2.md and wslproxy.org/waf.
Published by Workstation.
Product site: https://wslproxy.org · WAF: https://wslproxy.org/waf/
