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.

11 min read • View on GitHub • More from corazawaf

A precision lockbox mechanism where older gear trains feed into a cleaner modular engine through a shared protective gate. The image explains Coraza’s core idea: keep the security contract intact while replacing the runtime underneath it.
Coraza keeps the rule language stable while redesigning the engine around it.
Key Takeaways

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.

A single HTTP request enters a staged security corridor, splitting into header and body paths before hitting a match engine and an interruption lever. The scene explains how Coraza evaluates rules in phases instead of treating inspection as one opaque pass.
Coraza is phase-aware, not monolithic. It can inspect early, buffer when needed, and stop immediately when a deny action fires.

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.

DimensionCorazaModSecurityGeneric proxy filter
Rule compatibilitySecLang and CRS compatibleSecLang and CRS nativeUsually custom logic only
Runtime modelGo-native engine with pooling and phased evaluationC-based legacy engineLightweight checks, often shallow
Deployment surfacesGo apps, proxies, WASM sidecarsUsually web server integrationsProxy or edge only
Operational fitCloud-native migration pathLegacy web stack fitBest for simple allow/deny logic
Performance postureObject reuse, early exit, selective bufferingDepends on deployment and tuningFast 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.

Coraza does not scan as one block. It infers the earliest useful phase, then stops or continues based on rule outcomes.

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 typeNeeds body?Can run early?Why it matters
IP or header checksNoYesStops bad traffic before deeper inspection
Regex over argumentsSometimesOftenLets Coraza work as soon as the relevant fields exist
JSON body inspectionYesNoMust wait for buffered content
libinjection-style checksUsually body or fieldsDependsShort-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 surfaceBest forTrade-off
Go middlewareApplication-specific contextRequires app integration
Proxy integrationBroad traffic coverageLess business logic context
WASM sidecarPlatform-wide enforcementOperational complexity
Standalone libraryCustom embedsMore 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.