Interim edge mitigation for PHP CVE-2026-109618 (GHSA-w8hw-w9fx-j79w, "RCE via OOM corruption") and CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp), until patched PHP is deployed. VERSION 2026.10.6. Ships through this repo's own CI images; no WHP release needed.
209610: an ARGS_NAMES or FILES_NAMES entry with more than 16 [ is denied.
209611-209613: part-header budget (+4 per ARGS_POST/FILES entry, -1 per MULTIPART_PART_HEADERS value). Denied below -32, so a single part needs 37 or more headers.
209614-209615: more than 64 parts with an empty filename="" or filename= are denied.
209616: a multipart PHP_SESSION_UPLOAD_PROGRESS field is denied (-619).
The ids are inside the engine range 200000-209999. WHP's break-glass rule 991000001 already removes that whole range, so break-glass lifts these rules on current WHP.
Measured
Lab (HAProxy 3.0.11 from this image, curl 8.11 with quiche):
Blocked with 400: h1 chunked, h1 CL+TE, h1 -T -, h2 with no CL, h3 with no CL.
Passed with 200: h1/h2/h3 -F uploads (CL present), and chunked urlencoded (not multipart).
Real browsers against 192.168.1.148:
Chrome 155 over h2 and over h3 (forced QUIC): form submit with a file input, fetch(FormData) and XHR(FormData) all sent content-length and passed.
Only fetch with a ReadableStream body (duplex:'half') arrived without CL, and it got 400.
Firefox 153: form submit and XHR sent CL and passed.
Coraza: the WHP harness (scripts/tests/coraza-body-parse-harness/cve109618.go, Coraza v3.7.0 + CRS 4.25.0, real overrides.conf) passed with 0 failures in the enforce, detect_only and whp01 profiles.
Each attack also has a control run with the CVE block stripped, and every control passed (not blocked).
Break-glass check: with the ids moved out of the engine range, the emergency host is blocked again.
The coraza-spoa image (v0.7.1) starts with this file.
scripts/test-multipart-cve-mitigation.py is green, and turns red when either rule is mutated.
Limitation
Coraza sees only the first 16 KB of a body (tune.bufsize). An attacker who pads ahead of the abusive parts, or sends one part whose header block is over 16 KB, gets past the body rules. Both cases are recorded as LIMITATION in the harness. Only the no-Content-Length rule is enforced on the full request.
Interim edge mitigation for PHP CVE-2026-109618 (GHSA-w8hw-w9fx-j79w, "RCE via OOM corruption") and CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp), until patched PHP is deployed. VERSION 2026.10.6. Ships through this repo's own CI images; no WHP release needed.
## HAProxy (`templates/hap_listener.tpl`)
```
acl is_multipart_form req.fhdr(content-type) -m sub -i multipart/form-data
http-request deny deny_status 400 hdr x-whp-edge-block "multipart-without-content-length" if is_multipart_form !{ req.hdr_cnt(content-length) gt 0 }
```
It sits outside the `coraza_spoe_backend` block, so it applies with the WAF on or off, and trusted IPs are not exempt.
## Coraza (`coraza-spoa/overrides.conf`, 209610-209616)
- 209610: an ARGS_NAMES or FILES_NAMES entry with more than 16 `[` is denied.
- 209611-209613: part-header budget (+4 per ARGS_POST/FILES entry, -1 per MULTIPART_PART_HEADERS value). Denied below -32, so a single part needs 37 or more headers.
- 209614-209615: more than 64 parts with an empty `filename=""` or `filename=` are denied.
- 209616: a multipart `PHP_SESSION_UPLOAD_PROGRESS` field is denied (-619).
The ids are inside the engine range 200000-209999. WHP's break-glass rule 991000001 already removes that whole range, so break-glass lifts these rules on current WHP.
## Measured
- **Lab** (HAProxy 3.0.11 from this image, curl 8.11 with quiche):
- Blocked with 400: h1 chunked, h1 CL+TE, h1 `-T -`, h2 with no CL, h3 with no CL.
- Passed with 200: h1/h2/h3 `-F` uploads (CL present), and chunked urlencoded (not multipart).
- **Real browsers against 192.168.1.148:**
- Chrome 155 over h2 and over h3 (forced QUIC): form submit with a file input, `fetch(FormData)` and XHR(FormData) all sent content-length and passed.
- Only `fetch` with a ReadableStream body (`duplex:'half'`) arrived without CL, and it got 400.
- Firefox 153: form submit and XHR sent CL and passed.
- **Coraza:** the WHP harness (`scripts/tests/coraza-body-parse-harness/cve109618.go`, Coraza v3.7.0 + CRS 4.25.0, real overrides.conf) passed with 0 failures in the enforce, detect_only and whp01 profiles.
- Each attack also has a control run with the CVE block stripped, and every control passed (not blocked).
- Break-glass check: with the ids moved out of the engine range, the emergency host is blocked again.
- The `coraza-spoa` image (v0.7.1) starts with this file.
- `scripts/test-multipart-cve-mitigation.py` is green, and turns red when either rule is mutated.
## Limitation
Coraza sees only the first 16 KB of a body (`tune.bufsize`). An attacker who pads ahead of the abusive parts, or sends one part whose header block is over 16 KB, gets past the body rules. Both cases are recorded as LIMITATION in the harness. Only the no-Content-Length rule is enforced on the full request.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
PHP "RCE via OOM corruption" (GHSA-w8hw-w9fx-j79w) and the session
upload-progress variant (GHSA-6wmf-4rv5-p3rp), interim until patched PHP is
on every customer image.
HAProxy (hap_listener.tpl, every frontend render, WAF on or off):
deny 400 multipart/form-data with no Content-Length (HTTP/1.1 chunked,
HTTP/2-3 streamed bodies) -- vector (a), the post_max_size bypass.
Measured: Chrome 155 (h2 and h3) and Firefox 153 send content-length on
form submits, FormData fetch and XHR; only a ReadableStream fetch body
(duplex:'half') has none.
Coraza (coraza-spoa/overrides.conf, 209610-209616):
209610 ARGS_NAMES/FILES_NAMES with more than 16 '['
209611-613 part-header budget (4/part, deny 32 below zero)
209614-615 more than 64 empty-filename file parts
209616 multipart PHP_SESSION_UPLOAD_PROGRESS field
Ids sit in the engine range 200000-209999 that WHP's break-glass rule
(991000001) already removes, so no WHP release is needed for break-glass
to lift them. Each flips the engine On for itself, like the day-one
promotions, so they deny in every mode the sidecar runs in.
Limitation: Coraza sees only the first 16 KB of a body.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jknapp
merged commit 4345732dad into main2026-10-21 14:38:28 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Interim edge mitigation for PHP CVE-2026-109618 (GHSA-w8hw-w9fx-j79w, "RCE via OOM corruption") and CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp), until patched PHP is deployed. VERSION 2026.10.6. Ships through this repo's own CI images; no WHP release needed.
HAProxy (
templates/hap_listener.tpl)It sits outside the
coraza_spoe_backendblock, so it applies with the WAF on or off, and trusted IPs are not exempt.Coraza (
coraza-spoa/overrides.conf, 209610-209616)[is denied.filename=""orfilename=are denied.PHP_SESSION_UPLOAD_PROGRESSfield is denied (-619).The ids are inside the engine range 200000-209999. WHP's break-glass rule 991000001 already removes that whole range, so break-glass lifts these rules on current WHP.
Measured
-T -, h2 with no CL, h3 with no CL.-Fuploads (CL present), and chunked urlencoded (not multipart).fetch(FormData)and XHR(FormData) all sent content-length and passed.fetchwith a ReadableStream body (duplex:'half') arrived without CL, and it got 400.scripts/tests/coraza-body-parse-harness/cve109618.go, Coraza v3.7.0 + CRS 4.25.0, real overrides.conf) passed with 0 failures in the enforce, detect_only and whp01 profiles.coraza-spoaimage (v0.7.1) starts with this file.scripts/test-multipart-cve-mitigation.pyis green, and turns red when either rule is mutated.Limitation
Coraza sees only the first 16 KB of a body (
tune.bufsize). An attacker who pads ahead of the abusive parts, or sends one part whose header block is over 16 KB, gets past the body rules. Both cases are recorded as LIMITATION in the harness. Only the no-Content-Length rule is enforced on the full request.🤖 Generated with Claude Code