{"schema":"threatline.record/2","record":{"id":"CVE-2026-104827","aliases":["GHSA-g4f2-2pf3-2pwj"],"summary":"react/http: Unbounded HTTP Client Response Header Buffering Leads to Memory Exhaustion DoS","details":"### Summary\n\n`React\\Http\\Browser` and its lower-level HTTP stack impose no limit on the size of a response's header section while it is being received. `ClientRequestStream::handleData()` appends every incoming byte to an internal buffer and only scans that buffer for the `\\r\\n\\r\\n` (or `\\n\\n`) terminator, without ever checking its length. A remote server that withholds the terminator and keeps streaming can grow the client's memory without bound until PHP's `memory_limit` is exhausted and the process crashes.\n\nThis is an unauthenticated, network-reachable denial of service against any application that uses `react/http` as a client to fetch untrusted or attacker-influenced URLs, including via redirects.\n\n### Details\n\n`ClientRequestStream::handleData()` is bound directly to the underlying connection's `data` event, so every byte the peer sends is appended with no size check:\n\n```php\npublic function handleData($data)\n{\n    $this->buffer .= $data;\n\n    // buffer until double CRLF (or double LF for compatibility with legacy servers)\n    $eom = \\strpos($this->buffer, \"\\r\\n\\r\\n\");\n    $eomLegacy = \\strpos($this->buffer, \"\\n\\n\");\n    if ($eom !== false || $eomLegacy !== false) {\n```\n\nThe only exit from the buffering state is finding the header terminator or a connection close, so until it arrives the buffer grows monotonically for as long as the peer keeps sending.\n\nThe codebase already applies this class of limit elsewhere, but not symmetrically. `RequestHeaderParser` caps incoming **request** headers when acting as a server, and `Transaction::bufferResponse()` caps the response **body**, but only once the header section has already been parsed into a `Response`. Response header reception was the one stage with no limit at all.\n\n### PoC\n\nAn HTTP server that sends a valid status line and a partial header, then streams indefinitely without ever terminating the header section:\n\n```bash\nphp -r '$s=stream_socket_server(\"tcp://127.0.0.1:18080\"); $c=stream_socket_accept($s); fread($c,8192); fwrite($c,\"HTTP/1.1 200 OK\\r\\nX-Fill: \"); while (true) { fwrite($c, str_repeat(\"A\",1048576)); usleep(10000); }'\n```\n\nA client fetching it, with `memory_limit=64M`:\n\n```php\n$browser = new React\\Http\\Browser();\n$browser->get(\"http://127.0.0.1:18080/\")->then(\n    function () { echo \"ok\\n\"; },\n    function ($e) { echo get_class($e) . \": \" . $e->getMessage() . \"\\n\"; }\n);\n```\n\nClient memory grows steadily until the process dies with `Allowed memory size ... exhausted` inside `ClientRequestStream::handleData()`.\n\n### Impact\n\nRemotely triggerable, unauthenticated denial of service against any process using `Browser` to fetch from an attacker-controlled, compromised or otherwise untrusted endpoint, including one reached through a redirect. No user interaction and no special privileges are required. Because there is no upper bound on the header buffer, a single cheap connection can drive memory arbitrarily high and crash the process, taking down whatever event loop or worker it was running. Confidentiality and integrity are unaffected; availability is fully impacted for that process.","categories":["Frameworks"],"product":"react/http","vendor":"reactphp","ecosystem":"composer","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-g4f2-2pf3-2pwj","source_modified_at":"2026-10-15T20:09:58Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"composer","name":"react/http"},"range":">= 1.0.0, <= 1.11.0"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-104827","source_modified_at":"2026-10-16T17:11:59.859Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"http","vendor":"reactphp","versions":[{"status":"affected","version":">= 1.0.0, < 1.11.1"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-g4f2-2pf3-2pwj","source_modified_at":"2026-10-15T20:30:06.075181740Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"react/http","ecosystem":"Packagist","purl":"pkg:composer/react/http"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.0.0"},{"fixed":"1.11.1"}]}],"versions":["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"]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-g4f2-2pf3-2pwj","source_modified_at":"2026-10-15T20:09:58Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"composer","name":"react/http"},"version":"1.11.1"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-g4f2-2pf3-2pwj","source_modified_at":"2026-10-15T20:30:06.075181740Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"react/http","ecosystem":"Packagist","purl":"pkg:composer/react/http"},"version":"1.11.1"}],"cvss":7.5,"severity":"High","kev":{"listed":false},"epss":{"probability":0.00426,"percentile":0.35846,"score_date":"2026-10-23"},"published_at":"2026-10-15T18:19:32.785Z","modified_at":"2026-10-16T17:11:59.859Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-g4f2-2pf3-2pwj","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-15T20:09:58Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-104827","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-16T17:11:59.859Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-g4f2-2pf3-2pwj","fetched_at":"2026-10-23T18:48:36.087640Z","source_modified_at":"2026-10-15T20:30:06.075181740Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-104827","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/reactphp/http/security/advisories/GHSA-g4f2-2pf3-2pwj","tags":["x_refsource_CONFIRM"]},{"source":"CVE List","url":"https://github.com/reactphp/http/commit/2558622d0b76227c60c61eac8a61572cb6638e8c","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/reactphp/http/releases/tag/v1.11.1","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-g4f2-2pf3-2pwj","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"none","automatable":"yes","technical_impact":"partial","assessed_at":"2026-10-16T15:22:22.674618Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"product","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-16T17:11:59.859Z","content_hash":"d78131aea54e3cc0453f0d3c084fd903b3614e2604ba01516e807078da6b29f9"}}
