{"id":"GHSA-x424-64qh-5j54","summary":"react/http: A malformed HTTP chunked body can lead to a denial-of-service and peg the CPU","details":"### Summary\n\nA malformed HTTP message using `Transfer-Encoding: chunked` can drive `React\\Http\\Io\\ChunkedDecoder` into an infinite loop, pegging a CPU core and freezing the event loop. Because ReactPHP is single-threaded, one such message stalls the entire process for every client until it is killed.\n\nBoth directions are affected. `ChunkedDecoder` decodes chunked **request** bodies for `React\\Http\\HttpServer` and chunked **response** bodies for `React\\Http\\Browser`, so a server can be attacked by a malicious client and a client can be attacked by a malicious or compromised server.\n\n### Details\n\n`ChunkedDecoder::handleData()` loops `while ($this-\u003ebuffer !== '')` and relies on the buffer shrinking each iteration. Two states leave the buffer unchanged while the loop condition stays true.\n\n**Terminal-chunk trailer.** After the terminating `0` chunk, any remaining buffer is treated as trailer data to skip:\n\n```php\n} elseif ($this-\u003echunkSize === 0) {\n    $this-\u003ebuffer = (string)\\substr($this-\u003ebuffer, $positionCrlf);\n}\n```\n\nWhen the trailer holds no CRLF yet, `strpos()` returns `false`, PHP coerces that to `0` in `substr()`, and the buffer is never advanced. Neither the error guard (which requires a non-zero chunk size) nor the wait guard (which requires fewer than two bytes remaining) can fire, so the loop re-enters with identical state.\n\n**Off-by-one after a completed chunk.** Once a non-terminal chunk has been fully transferred, the \"chunk does not end with a CRLF\" error guard requires `strlen($this-\u003ebuffer) \u003e 2` while the wait guard requires `\u003c 2`. Exactly two non-CRLF bytes slip past both, and because the chunk is already complete nothing is consumed on the next iteration.\n\n### PoC\n\nRun the example server from the `reactphp/reactphp` README and send a malformed request. Note the missing trailing `\\r\\n`:\n\n```\nPOST / HTTP/1.1\\r\\nHost: x\\r\\nTransfer-Encoding: chunked\\r\\n\\r\\n0\\r\\nab\n```\n\nThe PHP process pegs at 100% CPU and stops answering legitimate requests. A body of `1\\r\\nAAB` triggers the second state.\n\nThe client side is reachable the same way: a `Browser` request to a server that answers with `Transfer-Encoding: chunked` and either malformed body shape hangs the client process.\n\n### Impact\n\nDenial of service. The affected process stops responding entirely and has to be killed.\n\nServers behind a reverse proxy that parses and re-frames HTTP, such as a typical nginx setup, are not affected on the **server** side, because the proxy normalises the request before it reaches PHP. That mitigation does not extend to the **client** side: outbound requests made with `Browser` reach the remote server directly, so an application fetching attacker-influenced URLs is affected regardless of what sits in front of it.","aliases":["CVE-2026-84997"],"modified":"2026-09-17T20:45:06.589484495Z","published":"2026-09-17T20:32:39Z","database_specific":{"nvd_published_at":"2026-09-16T15:18:00Z","cwe_ids":["CWE-835"],"severity":"HIGH","github_reviewed":true,"github_reviewed_at":"2026-09-17T20:32:39Z"},"references":[{"type":"WEB","url":"https://github.com/reactphp/http/security/advisories/GHSA-x424-64qh-5j54"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-84997"},{"type":"WEB","url":"https://github.com/reactphp/http/commit/b6d4688790adf3797071fcf88a3fc4225f30486a"},{"type":"WEB","url":"https://github.com/FriendsOfPHP/security-advisories/blob/master/react/http/CVE-2026-84997.yaml"},{"type":"PACKAGE","url":"https://github.com/reactphp/http"},{"type":"WEB","url":"https://github.com/reactphp/http/releases/tag/v1.11.1"}],"affected":[{"package":{"name":"react/http","ecosystem":"Packagist","purl":"pkg:composer/react/http"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0.6.0"},{"fixed":"1.11.1"}]}],"versions":["v0.6.0","v0.7.0","v0.7.1","v0.7.2","v0.7.3","v0.7.4","v0.8.0","v0.8.1","v0.8.2","v0.8.3","v0.8.4","v0.8.5","v0.8.6","v0.8.7","v1.0.0","v1.1.0","v1.10.0","v1.11.0","v1.2.0","v1.3.0","v1.4.0","v1.5.0","v1.6.0","v1.7.0","v1.8.0","v1.9.0"],"database_specific":{"last_known_affected_version_range":"\u003c= 1.11.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-x424-64qh-5j54/GHSA-x424-64qh-5j54.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]}