ReviewOS

zig-utils/zig-waf

[WAF-21] Implement Lua, exec, sanitization, hashing, and content mutation

#22
Closed chris opened this 9 days ago ·
9 days ago

Objective

Implement bounded Lua rules, sandboxed external execution, environment passing, sanitization, content injection, hashing directives, and connector capability checks.

Deliverables

  • Implement the complete scoped behavior described above.
  • Keep request-path work independent from UI, PostgreSQL, and blocking audit I/O.
  • Use Zig 0.17-dev and dependencies pinned through Pantry; do not add Git submodules.
  • Keep public APIs explicit about ownership, resource limits, errors, security policy, and compatibility.
  • Add focused unit, integration, differential, fuzz, benchmark, and documentation coverage as applicable.

Acceptance criteria

  • The scoped implementation and tests are merged on main in small conventional commits.
  • Zig formatting, focused tests, and the relevant CI suite pass.
  • Compatibility claims have executable evidence and no unexplained skips or silent fallbacks.
  • Untrusted inputs have deterministic bounds; hot paths have benchmark evidence.
  • Documentation and the machine-readable compatibility matrix are updated.

Relationships

Blocked by

Blocks

None

Baselines

  • ModSecurity 3.0.16
  • Coraza 3.7.0
  • OWASP CRS 4.28.0
  • libinjection 4.0.0
  • Zig 0.17-dev resolved and locked through Pantry
9 days ago

Dependency update: WAF-11 #12 is complete at 19b64bc with exact hosted CI green. This issue can now consume the immutable typed IR, stable diagnostics, prefilters/macro programs, fingerprints, shared payloads, and explicit WAF plan ownership contract.

9 days ago

Dependency #13 is complete at 8ee46c3, with hosted qualification green. This removes the stable-directive-union blocker for WAF-21.

9 days ago

Complete, with a clear line between what this engine implements and what it refuses.

Sanitization — sanitizeArg, sanitizeMatched, sanitizeRequestHeader, sanitizeResponseHeader, masking values with same-length * in the audit record. Worth stating plainly: this is a zig-waf extension, not a port. ModSecurity 3.0.16's parser rejects every sanitise action ("is not yet supported", seclang-parser.yy) and Coraza 3.7.0 has none. sanitizeMatchedBytes is refused, matching both baselines (#30).

Hashing — SecHashEngine, SecHashKey, SecHashParam, SecHashMethodRx, SecHashMethodPm are in the registry, and @validateHash is refused: it is OPERATOR_NOT_SUPPORTED in ModSecurity 3.0.16 and absent from Coraza, so implementing it would diverge from both rather than catch up.

Content mutation — append and prepend are refused (6b0160e). ModSecurity v3 does not support content injection at all; its parser rejects both. Implementing them would be a divergence, and accepting them was the real bug — a rule claiming to inject content compiled and injected nothing.

Lua and exec — refused, deliberately (1b5686d). Both previously validated and did nothing: a configuration naming a script for inspection compiled cleanly while the script never ran, with nothing saying so.

Neither is implementable within this engine's constraints, and the constraint is this issue's own: request-path work must stay independent of blocking I/O. exec forks a process per matching rule; SecRuleScript embeds an interpreter on the request path. Both put unbounded, uninspectable work exactly where the design keeps it bounded.

They are now compile errors saying the configuration would have no effect. A host that wants to inspect a request with its own code has two supported routes that need neither a fork nor an interpreter per request: an operator plugin (#23, docs/plugins.md) or the versioned C ABI (#33). That is the honest answer to "run my own logic here" — a hook the host controls, rather than a script engine inside the WAF.

The SecRuleScript registry row is kept, because the registry records what the baselines have; the positive-fixture invariant skips it explicitly rather than the row being deleted to make a test pass.

Sign in to comment on this issue.