Skip to content

fix(gateway): enforce bounded HTTP header mediation - #441

Merged
seonghobae merged 40 commits into
codex/coraza-header-enforcement-red-20260917from
test/440-gateway-header-mediation-red
Sep 24, 2026
Merged

seonghobae merged 40 commits into
codex/coraza-header-enforcement-red-20260917from
test/440-gateway-header-mediation-red

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

Refs #440.

Scope / writer authority

This is the serialized Wardnet-owned RED→GREEN lane for generic gateway HTTP mediation. Wardnet owns this gateway/SOC policy boundary. This PR does not copy EgressWeave transport authorization, quarantine-sandbox-runtime isolation, contextual-orchestrator routing, appguardrail logic, or sibling-owner implementation.

Established RED and bounded mediation repair

Hosted predecessor e32a620fa66232405adbd1603327bb5abcf55b4a reached the real loopback buyer fixture after checkout/toolchain/format/unit GREEN and failed five intended cases: admitted request Content-Type omitted; duplicate X-Admin-Token reached upstream; duplicate request Content-Type accepted; aggregate x-wardnet-app-meta beyond 16,384 bytes accepted; admitted upstream application/json replaced by synthesized application/octet-stream. Exact 4b938342ec1bc7f8dd2a1001cfcdf6a0136ccbca independently reproduced the same semantic RED in CI 35846750623 after 146 existing library tests passed; Fuzz 35846750936 was SUCCESS.

The source repair is wired through src/gateway_mediation.rs. It admits only bounded application metadata, rejects ambiguous request authority/singletons, strips credentials/authority/framing and dynamic Connection nominations, and reconstructs downstream responses from an explicit allowlist. Coraza parent #435 remains owner of its own authority/evidence seam and is adopted rather than duplicated.

The earlier complete candidate 68fc8ed6e6b9644d3406f0bf0c31113e7c1b76e0 obtained hosted exact-head CI 35864827991 SUCCESS and Fuzz 35864828031 SUCCESS.

Response-singleton finding and GREEN

Fresh standards review found that the candidate rejected duplicate response Content-Type but admitted repeated Location and Retry-After. RFC 9110 §10.2.2 defines Location = URI-reference and notes multiple Location field lines are invalid/non-interoperable; §10.2.3 defines Retry-After = HTTP-date / delay-seconds. WWW-Authenticate and bounded x-wardnet-app-meta intentionally retain multiplicity.

Test-only child #446 predecessor a6869e8b2fb1e3c6b9eb6e7d893950693297e864 established a real duplicate-Retry-After RED. Its initial duplicate-Location witness used 302 Found and was confounded because reqwest followed the redirect before Wardnet could inspect the original response envelope. Exact child b8b5804b655a424967252d8ac22172eb4a1338fb isolated the Location case on 201 Created; CI 35918347719, rust job 107375610618, completed format, locked workspace tests and strict Clippy successfully. #446 was then normally merged into this lane as two-parent merge bac6df06d810e977129d601628f14deb1a6381c7.

The Wardnet-owned minimum response-singleton repair rejects duplicate Content-Type, Location, and Retry-After while retaining legal multiplicity for WWW-Authenticate and bounded x-wardnet-app-meta.

The automatic-redirect specimen is a separate outbound-authority integration gap. Exact evidence and acceptance were handed to canonical EgressWeave Rust-consumer issue #237. Wardnet does not implement a second destination/DNS/redirect/proxy/TLS policy; EgressWeave still has no immutable GitHub Release for Wardnet to consume.

Content-Encoding finding and minimum causal repair

Issue #447 / test-only child #448 established the representation-metadata defect. Wardnet's active reqwest feature set does not enable transparent gzip/brotli/deflate decoding, so removing Content-Encoding while relaying coded bytes changes the representation contract. RFC 9110 §§5.2-5.3, 8.1 and 8.4 define Content-Encoding as representation metadata and allow ordered list-valued coding fields; it is not hop-by-hop Transfer-Encoding and must not be treated as a singleton.

Exact hostile child 8a254028faf4db0485ba8710945c2781a876fbed reached the intended tests in CI 35917178809, rust job 107371632198. Formatting and all 151 library unit tests passed first. Both real loopback buyer-path cases then failed semantically because coded request/response bytes crossed Wardnet while Content-Encoding: gzip was absent (left: None, right: Some("gzip")). This is the valid RED authorizing a source repair in this sole writer lane.

The minimum causal production repair first reached exact 16a0d0807692203dabc83823793dcefef087c661: content-encoding joined the bounded request/response mediation allowlists, legal repeated coding values are preserved in order, dynamic Connection: ... content-encoding nominations still strip the field, and no automatic decompression or foreign transport policy is introduced. Owned unit contracts cover ordered gzip, br multiplicity in both directions and nomination stripping.

#448 adopted that parent non-force through ordinary restack PR #449. Exact child 30b52cae32b7022237c552aa6224ebd7d9dfb632 retained only tests/gateway_content_encoding.rs as its effective child delta. Fresh exact-child CI 35941616793 completed SUCCESS and fresh review/thread inventory was empty. #448 was marked Ready and normally merged into this lane with fixed expected-head protection as two-parent merge cd3c5985fd6317ab80c888fe1e37786f94d780e8.

Current #441 is therefore exact cd3c5985fd6317ab80c888fe1e37786f94d780e8, based exactly on #435 11e7fabfca76e0051fa883905228a0dbe472f4df. Fresh exact-head CI 35962640235 and Fuzz 35962640233 are queued. Predecessor GREEN does not transfer after child integration.

Integration boundary

Before normal integration into #435 and later protected main on an unchanged exact lineage:

  1. current fix(gateway): enforce bounded HTTP header mediation #441 exact cd3c5985fd6317ab80c888fe1e37786f94d780e8 must reacquire terminal-valid repository evidence; its queued current-head checks are incomplete evidence and must not be blind-rerun;
  2. streaming/backpressure stays serialized in [P0] Stream generic gateway upstream responses with bounded backpressure #442/test(gateway): reproduce whole-response buffering #443 until this generic gateway mediation lane clears; outbound URL/address/DNS/peer/redirect/proxy/TLS authorization remains behind an immutable released EgressWeave contract;
  3. final exact-head format, locked workspace tests, strict Clippy, Fuzz/Security/SAST/CodeQL as applicable to the current stack layer, owned production statement/branch/edge/public-rustdoc evidence, realistic async buyer-path p95 <=20 ms, zero valid unresolved findings/threads, and fresh parent/protected-base compatibility must be reacquired on the integration lineage;
  4. only then may this stack advance normally. No stale predecessor, queued, skipped, cancelled, synthetic or merge-ref-only evidence is promoted to exact-head GREEN.

Release readiness remains separate: version/CHANGELOG/tag/package/immutable release/SBOM/provenance/reproducibility/rollback are required before a release-ready protected head. No force push, destructive rebase, self/model approval, gate weakening, routine administrator bypass, mutable sibling dependency, source copy, cross-service SQL, predecessor-evidence reuse, or blind rerun.

@coderabbitai

coderabbitai Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: cb15e0ee-b9d1-43aa-b1d8-01287b32de50

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae
seonghobae changed the base branch from main to codex/coraza-header-enforcement-red-20260917 September 21, 2026 18:11

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fresh exact-head review found one additional singleton-response ambiguity in src/gateway_mediation.rs: admit_response_headers() rejects duplicate Content-Type but currently admits multiple Location and Retry-After field lines because both are allowlisted and appended with multiplicity. RFC 9110 §10.2.2 defines Location = URI-reference, explicitly states the field value consists of a single URI-reference, and notes that multiple Location field lines are invalid/interoperability-hostile. §10.2.3 likewise defines Retry-After = HTTP-date / delay-seconds as one value. WWW-Authenticate is intentionally different and may retain list/multiple challenge semantics.

Please extend the #440 hostile contract before wiring this module into the live proxy path: duplicate Location and duplicate Retry-After from a real loopback upstream must fail closed without relaying an ambiguous field/body as a successful buyer response; a single value for each remains preserved. Minimum causal source repair should treat these two as response singletons alongside Content-Type, without collapsing multiplicity for WWW-Authenticate or x-wardnet-app-meta. Keep this in the existing #441 source-writer lane rather than opening a second production writer.

Copy link
Copy Markdown
Contributor Author

Exact hostile RED is now valid for the response-singleton follow-on. Child #446 at a6869e8b2fb1e3c6b9eb6e7d893950693297e864 ran hosted CI 35865544601 / rust job 107196068485: checkout, toolchain and cargo fmt --check passed; 151 library tests and the existing gateway mediation suite passed; then both loopback hostile cases failed semantically because duplicate upstream Retry-After was relayed as HTTP 429 instead of fail-closed 502 and duplicate upstream Location was relayed as HTTP 404 instead of 502. This is owner RED, not runner/bootstrap noise.

Minimum causal repair is now on this sole source-writer lane at exact 29a35163fc5bab860f247a68a6b1d5f797d73182: admit_response_headers() rejects duplicate Location and Retry-After alongside duplicate Content-Type, while preserving intentional multiplicity for WWW-Authenticate and bounded x-wardnet-app-meta; the owned unit contract covers all three response singletons. No transport/egress/quarantine/orchestrator/appguardrail owner logic was copied.

#446 was non-force restacked by ordinary two-parent merge to exact 8ae44f90dec252140ad65075a96ad1c8b256f0ea, retaining only tests/gateway_response_singleton_mediation.rs as its effective child delta. Exact-head CI/Fuzz for the source repair and child GREEN are pending; do not merge or claim GREEN until those unchanged heads execute.

chore(stack): adopt repaired gateway parent into #448
@seonghobae seonghobae changed the title test(gateway): reproduce bounded header mediation gap fix(gateway): enforce bounded HTTP header mediation Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

Fresh exact-head documentation review found a code-current drift introduced by the #447 minimum repair. At 16a0d0807692203dabc83823793dcefef087c661, src/gateway_mediation.rs now admits content-encoding in both bounded request and response allowlists, preserves its list-valued multiplicity, and still applies dynamic Connection nomination stripping. docs/security/gateway-header-mediation.md still describes the pre-repair allowlists and calls Content-Encoding a separate follow-on acceptance gap.

Do not move #441 solely to repair the prose while test-only child #448 exact 30b52cae32b7022237c552aa6224ebd7d9dfb632 is waiting on exact-base/current-head CI: that would unnecessarily invalidate the child evidence/base. After #448 reaches unchanged-head GREEN and is normally integrated into #441, update this same #441 writer lane so the security doc states Content-Encoding is admitted representation metadata (not hop-by-hop framing), keeps ordered/list semantics, remains subject to dynamic Connection stripping, and does not imply decompression or ownership of EgressWeave transport policy. Then reacquire all exact-head gates on the resulting #441 head.

This is a deferred same-writer documentation repair, not authorization for a parallel source/docs PR.

…oding-red

test(gateway): preserve coded representation metadata
@seonghobae
seonghobae marked this pull request as ready for review September 24, 2026 10:00
@seonghobae
seonghobae merged commit 534a48b into codex/coraza-header-enforcement-red-20260917 Sep 24, 2026
4 checks passed
@seonghobae
seonghobae deleted the test/440-gateway-header-mediation-red branch September 24, 2026 10:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant