ReviewOS

zig-utils/zig-waf

[WAF-27] Implement XML, XPath, XSD, and DTD processing

#28
Open chris opened this 9 days ago ·
9 days ago

Objective

Implement namespaces, XPath variables, schema validation, safe external-entity defaults, expansion limits, encodings, and an isolated Pantry-managed libxml2 adapter.

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

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

WAF-08 (#9) is complete and its collection contract is now available on main at 531cc68. Hosted qualification is green: https://github.com/zig-utils/zig-waf/actions/runs/29935997519

This removes the WAF-08 dependency for this issue. Preserve the published ownership, phase-gating, origin, bounded-storage, selector/error, and derived-family contracts when implementing this scope.

9 days ago

The XML body-processing slice of this issue is implemented (commits landed referencing the body-processor framework #27).

To avoid a C XML dependency, I wrote a new from-scratch package zig-utils/zig-xml@0.1.0 — a lenient, allocation-light XML/HTML tokenizer, XXE-safe (no DTD/external-entity resolution) — released to the pantry registry, and consumed it in zig-waf.

Done:

  • e889b17 XML request bodies populate the XML collection under //@* (attribute values) and /* (text/CDATA) — the selectors OWASP CRS inspects — pinned to Coraza's XML processor; entities decoded, CDATA literal.
  • 9d6d350 consume zig-xml@0.1.0 from the registry; c73fd39 docs/matrix.

Remaining for this issue: full XPath evaluation (beyond the //@* and /* selectors), @validateSchema (XSD), and @validateDTD. These need a fuller XPath/schema layer and are a separate slice.

9 days ago

Status, with what is done and what genuinely remains.

Done

  • Safe external-entity defaults — and they are structural, not a setting (a5aba65). The tokenizer decodes character references only and has no DTD processor, so there is no external-entity resolution to switch off. Pinned by tests: a body declaring <!ENTITY xxe SYSTEM "file:///etc/passwd"> puts the file's contents nowhere a rule can read, and a billion-laughs body parses to little rather than consuming the process. The day an XML backend gains DTD support is the day XXE becomes possible by default, which is exactly what those tests are there to catch.
  • Expansion limits — same origin: nothing expands, so nothing needs bounding. The body itself is bounded by the request-body limits (#25).
  • XML variables CRS uses — XML://@* (attribute values) and XML:/* (text and CDATA), populated through the zig-xml tokenizer with character references decoded, matching Coraza and what OWASP CRS 4.28 actually inspects. Those two selectors are all CRS 4.28 uses, verified against its rule files.
  • Unimplemented operators refused, not ignored — @validateSchema and @validateDTD fail to compile with a diagnostic saying the rule could never match, rather than sitting in a ruleset looking like validation (#38).

Not done, and not claimable

  • General XPath variables. Only the two selectors above resolve. A real XPath evaluator — node tests, axes, predicates, namespace prefixes — is a substantial component and I will not claim it from a corpus of two selectors.
  • Schema validation (XSD) and DTD validation. These need libxml2, which is the issue's own stated plan ("isolated Pantry-managed libxml2 adapter"). The package is in pantry.lock as a transitive dependency but no static library is extracted, and the adapter has to be written with libxml2's own entity resolution disabled — the classic XXE source, and the reason it needs care rather than a quick link.
  • Namespaces and encoding declarations beyond what the tokenizer passes through.

Leaving this open with the boundary stated rather than closing it on the parts that are finished. The safety properties are the ones that matter for deployment today, and they are tested; the XPath and schema work is a real component that deserves its own focused effort.

Sign in to comment on this issue.