Coraza WAF: The Go Engine Rewriting ModSecurity for Cloud-Native Traffic
A deep dive into how Coraza preserves SecLang compatibility, trims runtime overhead, and pushes WAF logic into Go apps, proxies, and WASM sidecars.
- Coraza’s real innovation is not a new rule language, but a new runtime that preserves SecLang and CRS compatibility while fitting cloud-native deployment models.
- The engine is built to stop work early, reuse memory aggressively, and evaluate rules as soon as the needed data exists.
- Its value is strongest for teams that want to keep their existing WAF investment while moving from legacy C-based infrastructure into Go, proxies, and WASM.
- Coraza is a migration tool and a performance project at the same time, which is why its architecture matters as much as its compatibility claims.
Why Coraza exists
The easiest way to misunderstand Coraza is to call it "a Go WAF." That is true, but not useful. The deeper story is that Coraza tries to carry a trusted security contract, SecLang plus the OWASP Core Rule Set, into runtime environments that did not exist when ModSecurity became the default.
That matters because a WAF is only half code and half memory. Security teams do not just move a binary around. They move years of rule tuning, incident history, and operational trust. Coraza is designed to preserve that investment while changing the execution model underneath it.
The compatibility promise
Coraza’s headline promise is simple: keep existing SecLang rules working. That means rule authors can bring familiar syntax, operators, transformations, and CRS patterns without rebuilding the policy layer from scratch.
| Dimension | Coraza | ModSecurity | Generic proxy filter |
|---|---|---|---|
| Rule compatibility | SecLang and CRS compatible | SecLang and CRS native | Usually custom logic only |
| Runtime model | Go-native engine with pooling and phased evaluation | C-based legacy engine | Lightweight checks, often shallow |
| Deployment surfaces | Go apps, proxies, WASM sidecars | Usually web server integrations | Proxy or edge only |
| Operational fit | Cloud-native migration path | Legacy web stack fit | Best for simple allow/deny logic |
| Performance posture | Object reuse, early exit, selective buffering | Depends on deployment and tuning | Fast for simple checks, limited depth |
This is not marketing fluff. In WAF land, compatibility is the product. If you cannot reuse the rules your team already trusts, the migration cost is not technical, it is organizational.
Inside the WAF lifecycle
Coraza turns an HTTP request into a Transaction, then runs that transaction through phases. Some rules can be evaluated as soon as metadata exists. Others need the body. If a rule matches and its action interrupts, processing stops and the middleware can return a denial immediately.
The important shift is mental. A WAF is often treated like a black box that inspects everything after the fact. Coraza behaves more like a staged decision pipeline. That reduces wasted work and makes early interruption possible.
// Simplified lifecycle sketch
req := newHTTPRequest()
tx := waf.NewTransaction(req)
for _, phase := range tx.Phases() {
tx.LoadPhaseData(phase)
matches := tx.EvaluateRules(phase)
if tx.Interrupted() {
return tx.InterruptionResponse()
}
_ = matches
}
return tx.Continue()
The tricks that keep it fast
Coraza’s performance story is less about one magic optimization and more about a stack of careful choices. The codebase leans on sync.Pool for transaction reuse, immutable config cloning to avoid shared-state surprises, regex memoization to reduce repeated compilation, and body buffering that spills to disk instead of eating RAM.
That combination matters because WAF workloads are awkward. They are stateful, branchy, and expensive. If you allocate too much, latency spikes. If you buffer too aggressively, uploads become a memory risk. Coraza is trying to make the expensive parts predictable.
Why immutable config helps
The configuration API clones before it mutates. That looks small, but it protects one of the hardest properties in security software: determinism. When multiple services or goroutines share a WAF instance, config objects need to behave like snapshots, not shared notebooks.
Why phased evaluation matters
Phased evaluation is the reason Coraza can feel responsive without becoming shallow. A rule that only depends on request metadata should not wait for a full body parse. A body-dependent rule should not run before the body exists. Coraza tries to infer that boundary and shift work earlier when it can.
| Rule type | Needs body? | Can run early? | Why it matters |
|---|---|---|---|
| IP or header checks | No | Yes | Stops bad traffic before deeper inspection |
| Regex over arguments | Sometimes | Often | Lets Coraza work as soon as the relevant fields exist |
| JSON body inspection | Yes | No | Must wait for buffered content |
| libinjection-style checks | Usually body or fields | Depends | Short-circuits common attack patterns efficiently |
That is a latency story, but it is also a cost story. Every phase you skip is CPU you do not spend and memory you do not touch.
Where Coraza fits in the stack
Coraza is not pinned to one insertion point. It can sit inside Go applications as middleware, live in proxy stacks, or travel into WASM-based environments such as Envoy and Traefik integrations. That flexibility is part of the design, not a side effect.
For platform teams, this matters because the place where you enforce policy is often more important than the policy itself. App-layer middleware gives you context. Proxy-layer deployment gives you reach. WASM sidecars give you a way to add inspection without rewriting services.
| Deployment surface | Best for | Trade-off |
|---|---|---|
| Go middleware | Application-specific context | Requires app integration |
| Proxy integration | Broad traffic coverage | Less business logic context |
| WASM sidecar | Platform-wide enforcement | Operational complexity |
| Standalone library | Custom embeds | More engineering ownership |
Coraza’s advantage is that the same rule engine can move between those surfaces. That reduces policy drift across layers.
What it means for teams replacing ModSecurity
If your team already runs ModSecurity plus CRS, Coraza is attractive because it offers continuity. The upside is lower migration friction and a modern Go runtime. The downside is that WAF tuning does not disappear. You still need to manage exceptions, false positives, buffering limits, and deployment placement.
That is the right trade. A modern WAF should make the engine easier to operate without pretending the security work is solved. Coraza does not remove the need for policy care. It removes a lot of reasons to keep the old runtime around.





