A fast, low-memory Web Application Firewall delivered as a Traefik plugin.
Status: v0.4.6 released. The current release includes audit labels, webhook relay delivery, signed artifacts, SBOMs, Helm OCI packaging, Kustomize overlays, an O(1) reputation limiter, bounded percent-decode-to-fixpoint normalization, an expanded signature pack, User-Agent SQLi suffix probing, over-cap body-prefix inspection, an offline config validator, relay SSRF hardening, optional relay admin auth, and new fuzz targets. v0.4.6 keeps WAF behavior compatible while removing redundant configured-engine dispatch and policy allocations, avoiding disabled audit-log serialization, bounding zero-capacity dead-letter queues, enforcing documented unsafe boundaries, and centralizing checksum-verified wasi-sdk 33 builds. See CHANGELOG.md for the full list, THREAT_MODEL.md for what the WAF is and is not designed to catch, and docs/configuration.md for the Middleware config reference. The webhook protocol contract lives in docs/webhook-protocol.md.
purple-wolf inspects every HTTP request reaching a route protected by one
of its Middlewares and either lets it through or returns 403 Forbidden.
Inspection covers headers, URL, query parameters, and the request body (up
to a configurable cap) using a hybrid engine: libinjection (SQLi/XSS),
aho-corasick literal signatures, structural anomaly checks, and per-IP
rate limiting / deny-listing.
internet → Traefik (TLS, routing, your existing setup)
└─ compiles purple-wolf.wasm with wazero's shared cache
└─ for each request matching a route that chains a
purple-wolf Middleware:
borrow a guest instance from the host pool
→ normalize → inspect enabled groups → decide policy
→ emit noteworthy audit line
→ block with 403 or restore the body and call backend
- Three crates:
purple-wolf-core(the engine, pure Rust, native +wasm32-wasip1),purple-wolf-traefik(http-wasm guest plugin), andpurple-wolf-relay- a standalone webhook fan-out service that tails Traefik's audit-log stream and delivers HMAC-signed events to subscribers. - Multi-tenant by construction: each
Middlewareconfig creates a separate host middleware. The http-wasm host pools guest instances for concurrency; every guest has independent WASM memory, immutable config, detector state, and reputation buckets. - Push delivery: the WAF stays focused on detection; if you want signed webhooks to a SIEM, Slack, or per-tenant subscriber, run the relay alongside Traefik. See the relay's README and the webhook protocol spec.
Run Traefik, the WASM plugin, a backend, the relay, and an HMAC-verifying subscriber:
docker compose -f examples/demo/docker-compose.yml up --buildThen try the requests in examples/demo/README.md.
Install the OCI Helm chart in monitor mode:
helm install purple-wolf oci://ghcr.io/guaracloud/charts/purple-wolf \
--version 0.4.6 \
-f charts/purple-wolf/values.monitor.yamlKustomize users can start with:
kubectl apply -k deploy/kubernetes/overlays/monitor-modeThe chart and Kustomize overlays render monitor/enforce Middleware examples but
do not attach them to any route. Attach purple-wolf-monitor to selected
IngressRoutes first, review audit output, then opt in to enforce mode.
Before production use, verify checksums, Cosign signatures, SBOMs, image digests, and the release manifest:
gh release download v0.4.6 --repo guaracloud/purple-wolf --dir purple-wolf-releaseFollow docs/release-verification.md and deploy
digest-pinned image references from release-manifest.json.
Run the relay when you want signed webhooks to a SIEM, Slack bridge, or tenant
subscriber. See docs/operations.md,
docs/helm.md, and
docs/kubernetes-production.md.
For the full per-field Middleware reference, see
docs/configuration.md. Existing raw files under
examples/ remain educational examples; production users should
prefer Helm or Kustomize.
Same Kubernetes topology, same Traefik v3.1, same backend, same 200 m CPU / 1 GiB resource budget, same OWASP CRS corpus - only the WAF engine differs. Two rounds; round 2 expanded the matrix to a no- WAF baseline pod, a ramp-to-break sweep, 12 CRS attack classes (4 536 vectors), a 10-minute soak with resource sampling, and a small functional robustness suite.
Headline results (full methodology + tables + caveats in
docs/benchmark.md):
- Isolated WAF overhead: +0.1–0.2 ms p99 vs a Traefik-only baseline pod. Invisible at typical backend latencies.
- Sustained throughput at the same resources: purple-wolf is clean to ~8 000 RPS; Coraza http-wasm collapses at 500 RPS. About 16–20× more sustained RPS for purple-wolf at the tested ceiling.
- Detection across 12 CRS rule classes (4 536 vectors): purple-wolf 14.55 % overall TPR vs Coraza inline-PL1 6.11 % - 2.4× more attacks blocked, with 0 % FPR on the benign corpus for both. Java (+26.5 %), RCE (+6.3 %), XSS (+5.1 %) are the biggest margins.
- Memory under sustained load: stable in an 80–96 MiB band over a 10-minute soak at 1 000 RPS, no drift. Coraza peaked at 946 MiB during round 1 (OOM-killed five times at the original 512 MiB ceiling).
- Closed benchmark-surfaced gaps: round 2 found misses for
User-Agent SQLi with a
Mozilla/prefix and bare;wgetquery payloads. v0.4 closes both with the UA suffix probe andrce_cmdsignatures; the benchmark numbers above remain the last published live-stack run, so a rerun is still needed to publish updated live-stack coverage.
The benchmark is reproducible end-to-end:
benchmarks/runner/round2/run-all-round2.sh.
Raw JSONL + CSV outputs from the published runs live under
benchmarks/results/.
What the benchmark is not: a claim that purple-wolf is "better" than Coraza. Coraza's native (Go-binding) Traefik integration is faster and rule-richer than the http-wasm path measured here, and full OWASP CRS catches far more atomic-token tests than either engine in this comparison - at higher FPR. The comparison is honestly bounded: same plugin shape, same resource ceiling, same yardstick.
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --all-targets
cargo test --workspace --doc
cargo deny check
cargo build --locked -p purple-wolf-traefik --target wasm32-wasip1 --releaseWASM builds require wasi-sdk. To use the repository's cross-platform Docker
builder (including on arm64 hosts):
mkdir -p target/wasm-docker
docker build -f examples/demo/Dockerfile.wasm-builder -t purple-wolf-wasm-builder .
docker run --rm -v "$PWD/target/wasm-docker:/out" purple-wolf-wasm-builderFor a native toolchain install, download wasi-sdk and set its root:
# Download wasi-sdk from https://github.com/WebAssembly/wasi-sdk/releases
export WASI_SDK_PATH=/path/to/wasi-sdkDual-licensed under MIT OR Apache-2.0. libinjection (vendored C) is BSD-3-Clause.