Objective
Compile and execute the stable ModSecurity 3.0.16 / Coraza 3.7.0 union of rule metadata and non-disruptive actions without reparsing action strings on the request path. Metadata becomes immutable typed plan state; a successful rule/operator match produces a bounded effect batch that mutates only the isolated transaction and its configured persistent session. Logging actions produce immutable event intent and never perform synchronous audit, telemetry, UI, or database I/O.
Behavioral contract
Typed metadata
- Compile
id,rev,msg,logdata, repeatabletag,severity,maturity,accuracy, andverinto typed immutable rule metadata with source spans. - Preserve unsigned 64-bit external IDs and the WAF-11/WAF-13 uniqueness/chain invariants. Chain members inherit head metadata according to upstream semantics without duplicating identity.
- Accept numeric severities 0–7 and case-insensitive names
EMERGENCY,ALERT,CRITICAL,ERROR,WARNING,NOTICE,INFO, andDEBUG; retain the canonical numeric value. - Validate bounded numeric maturity/accuracy values and reject malformed, duplicate-ID, empty-required, or out-of-range metadata with stable source diagnostics. Repeated singleton metadata uses the last effective value, matching ModSecurity; tags remain ordered and repeatable.
- Preserve ordered duplicate tags. Compile macro-bearing
msg,logdata, and tag values once; expand against the post-action transaction state when the match record is finalized. - Populate a read-only per-match
RULEcollection (id,rev,msg,logdata,severity,maturity,accuracy,ver) so%{RULE.*}and subsequent actions observe the active rule.
Match/capture input and event intent
- Expose a bounded
MatchContext/equivalent input carrying the matched variable name/value, source range, and up to ten operator capture ranges. captureclears priorTX.0–TX.9state, then copies capture 0 and present subgroups in order. Missing optional groups remain absent; out-of-range or overlapping byte slices cannot escape the supplied matched value.- A completed action application returns immutable/bounded match intent containing rule identity, expanded message/logdata/tags, severity, matched-variable evidence, log/audit decisions, and action-effect counts.
log/nologandauditlog/noauditlogare paired last-effective-value families already materialized by WAF-13. They set event intent only; WAF-29/WAF-30 consume it asynchronously.nologdoes not silently erase explicit audit intent, andnoauditlogdoes not suppress debug/match state required by policy. Exact ModSecurity/Coraza union choices are differential fixtures.
Environment and collection mutation
setenv:NAME=VALUEexpands both bounded syntax and value into the transaction-localENVcollection. It never mutates process-global environment state; this is an intentional thread-safety/security hardening over upstream implementations.setvarsupports case-insensitiveTX,IP,SESSION,USER,GLOBAL, andRESOURCEcollection names, macro-bearing keys/values, set-to-one, assignment, deletion, and signed add/subtract.- Arithmetic follows the already-pinned ModSecurity numeric-prefix/zero-on-invalid compatibility contract, uses checked signed 64-bit math, and reports overflow without corrupting existing state.
initcolsupports the stable persistent namespaces and macro-expanded collection keys.setsid,setuid, andsetrscinitialize/bind the corresponding collection and compatibility scalar through the same code path.expirevarparsesCOLLECTION.key=seconds, requires an initialized persistent collection, uses checked timestamps, and stages expiry through the configured persistence session.deprecatevarparsesCOLLECTION.key=amount/period, validates positive bounded operands, performs deterministic elapsed-time decay using the injected monotonic/real clock contract, and updates the persistent value/timestamp without request-path sleeps.- Persistent actions honor the WAF-09 explicit backend capability and fail-open/fail-closed policy. Production behavior never substitutes an in-memory or SQLite backend silently.
Ordering, chains, and atomicity
- Execute effective non-disruptive actions in source order using the WAF-13 post-overlay action range.
- Metadata is available before action expansion;
logdataand final event strings expand after collection mutations, matching Coraza's post-action requirement and ModSecurity-compatible macro visibility. - Actions attached to an individual chain member execute only when that member matches; final chain-head event/disruptive handling occurs only after the complete chain succeeds. WAF-15 consumes the resulting flow state.
- Parse, classify, validate, and compile every supported action while building the candidate plan. Published request-path execution performs no action parsing, regex compilation, filesystem/network/database lookup, or unbounded allocation.
- Expansion and semantic validation complete into a bounded effect batch before local mutation. A failed preflight leaves transaction state unchanged. Commit-time persistent failures follow explicit configured policy and remain observable.
- Every count and byte total is bounded independently: captures, tags, metadata bytes, macro output, effect count, environment entries, collection writes, and event-intent storage.
Public and plan interfaces
- Typed
RuleMetadataand compiled non-disruptive action/effect descriptors addressable byRuleId/ActionIdwith source spans. MatchContextuses borrowed input with explicit lifetime; finalized match/event intent owns bounded copies needed after connector buffers move.Transaction.applyMatchedRule(or equivalent) applies one matched rule/member and returns typed outcome/errors without performing disruptive flow or blocking I/O.- Read-only accessors expose active rule metadata, event intent, capture values, environment values, and applied-effect evidence.
- Stable diagnostics distinguish invalid metadata, unknown severity, invalid collection mutation, uninitialized persistent collection, invalid TTL/decay, capture bounds, capacity, macro, arithmetic, and backend failures.
- Compiler ABI and public feature discovery change when the typed plan/runtime contract changes.
Deliverables
- Typed metadata/action IR, validation, diagnostics, fingerprinting, and limits.
- Transaction-local
RULEmetadata projection and bounded match context. - Capture semantics for
TX.0–TX.9. - Log/audit intent and owned expanded match-event metadata.
- Transaction-local
setenvwithout process-global mutation. setvarset/delete/add/subtract for the TX namespace.setvarset/delete/add/subtract for persistent namespaces.initcol,setsid,setuid, andsetrscpersistent binding.expirevaranddeprecatevartimestamped persistence behavior.- Ordered chain-member action application and bounded effect preflight/commit.
- Allocation-failure, hostile-input, differential, fuzz, corpus, and hot-path benchmark coverage.
- Documentation and machine-readable compatibility evidence.
Acceptance criteria
- Every scoped action has positive, negative, ordering, macro, allocation-failure, and resource-limit coverage.
- Differential fixtures pin intentional stable-union behavior to exact ModSecurity 3.0.16 and Coraza 3.7.0 revisions; CRS 4.28 action combinations compile with zero unexplained exclusions.
- Capture tests cover 0–9, missing groups, empty captures, stale-value clearing, hostile ranges, and binary matched values.
- Mutation tests cover dynamic keys, empty values, deletion, signed arithmetic, overflow, missing initialization, expiry, decay, fail-open/fail-closed, and chain-member timing.
- No test observes process-global environment mutation from
setenv. - Failed preflight leaves local/persistent staged state unchanged; backend failures are typed and observable.
- Request-path benchmarks report actions/s, p50/p95/p99 application latency, allocations, bytes copied, and effect/event storage for no-op metadata, CRS-style TX scoring, capture, and persistent action mixes.
- Focused tests, full
zig build test,zig build check, corpus/fuzz/benchmark gates, formatting, and hosted CI pass on the exact closing SHA. - Work lands directly on
mainin small conventional commits with issue/commit/run links.
Relationships
- Parent: WAF-00 #1
- Unblocked by: WAF-09 #10, WAF-11 #12, WAF-13 #14
- Runtime lifecycle: WAF-06 #7
- Operator/capture producer: WAF-17 #18
- Blocks: WAF-15 #16, WAF-29 #30, WAF-30 #31
Baselines and upstream references
- ModSecurity 3.0.16 commit
7ea9fefbe0ba409d8733b4d682c8c4c059cd028d:src/actions/{capture,set_var,set_env,init_col,expire_var,severity,log_data}.*and action regression cases. - Coraza 3.7.0 commit
27069d06c896be74b77b9a6c0b539a0cbfaca360:internal/actions/{capture,setvar,setenv,initcol,expirevar,severity,logdata}*and chain action tests. - OWASP CRS 4.28.0 commit
55b09f5acfd16413e7b31041100711ceb7adc89c: TX scoring, capture, metadata, and persistent-action corpus. - Zig 0.17-dev is locked through Pantry; no Git submodules or runtime PCRE/TLS/database substitutions.