Light WAF is one open-source project in two layers: a core that is the security datapath, and components that run it at scale. Here is where the line sits, and the rules that keep the core small enough to audit.
The core is the security datapath. It must be fully useful on a single node, self-sufficient, and small enough to audit.
The components add scale, governance and team operability — never baseline detection.
Understanding and inspecting a protocol is core. Running it at scale, with governance, is a component.
Every detection module lives in the core, including gRPC and GraphQL inspection. A single node runs standalone: proxy, phased pipeline, normalization, anomaly scoring, TLS from file, single-node rate limiting, config and hot reload.
Every component plugs into a public trait through the embedding builder. The waf-enterprise binary is the core with every component wired in — turn each one off and you have exactly the waf binary's behavior.
Read it as: the core gives you the whole datapath; the components add scale, governance and evidence around it. Both are Apache-2.0.
| Area | Core · waf | Components add · waf-enterprise |
|---|---|---|
| Detection & inspection | Every module — SQLi, XSS, RCE, SSRF, … — plus gRPC & GraphQL inspection and the CRS engine. | Curated rule content; GraphQL, gRPC and OpenAPI schema enforcement; bot detection. |
| Rate limiting & state | Single-node L7 token bucket (the StateStore trait + in-memory impl). | One budget shared across the fleet via Redis, plus IP reputation and threat feeds. |
| TLS | Termination from file (rustls, HTTP/1.1 + HTTP/2 via ALPN). | ACME issuance & hitless rotation, mutual TLS, certificates shared across nodes. |
| Rules | seclang / ModSecurity parser + evaluation engine. | Curated content, and governed publish / rollback with a per-node agent. |
| Observability | Prometheus /metrics + a structured JSON decision log. | Dashboard, retention, blocked-request drill-down, full request capture, alerting. |
| Access control | — | RBAC, SSO (OIDC), server-side sessions, revocable service tokens. |
| Audit & compliance | — | A signed, hash-chained audit log and on-demand SOC2 / PCI evidence bundles. |
| SIEM | Raw logs (your own shipper). | A push forwarder — normalized, at-least-once, with visible lag. |
| WASM plugins | The runtime (Proxy-Wasm on wasmi). | Detached-signature verification before a plugin loads. |
| Deployment | Run the waf binary anywhere (systemd, a container). | Kubernetes-native: Helm charts, a WafProxy operator, GitOps & Gateway API examples. |
For every component, the core defines a public trait; the component provides an implementation and injects it through the builder. Nothing is patched into the core.
// embed the core as a library and inject implementations of its public traits let store = RedisStore::connect_with_options(&url, RedisStoreOptions::default())?; let proxy = Proxy::builder(&config) .state_store(Arc::new(store)) // StateStore .cert_source(Arc::new(AcmeCertSource::new(..))) // TlsCertSource .module_factory(move || build_modules(&cfg)) // WafModules, rebuilt on every reload .build().await?; // every seam has a default → an empty builder equals the plain waf proxy.
StateStore, TlsCertSource and WafModule are public traits. The components implement them — and so can you. If a module fails to rebuild on a SIGHUP reload, the reload is aborted and the last-good modules stay active.
The boundary is a written, normative policy in the repository — these are the parts that matter when you deploy it.
Components depend on the core's public API only; the core never depends on a component. A component never forks or patches the core.
The core needs no Redis, no Postgres and no control plane. A single node is fully protected by the waf binary on its own.
The control plane reads telemetry off to the side. It never sits between clients and your backend — it cannot add latency or fail a request.
Every component is opt-in. An empty builder, or a config with every component off, behaves exactly like the core.
From 1.0 the extension traits, the builder and the config schema follow SemVer, so your own implementations keep building.
One memory-safe Rust foundation; TLS is rustls. No OpenSSL is linked into any shipped binary.
Core and components ship together on the same version. The control plane, governance, node agent and operator are shipped as container images and Helm charts instead.
The core, the components, the control plane, the charts and the operator are all Apache-2.0 — permissive, with an explicit patent grant. Use it, embed it, run it as a service.
Contributions are accepted under the same license, with a Developer Certificate of Origin sign-off (git commit -s) — no CLA to sign.
The license covers the code, not the name (Apache-2.0 §6): fork it freely, but don't present a fork as Light WAF itself.
Run the core today; turn on the components when a fleet and an audit ask for them.