{"id":"GHSA-jq4m-q6p2-8gwc","summary":"Hackney: Per-chunk timeout with unbounded body accumulation enables slow-drip OOM","details":"### Summary\n\n`hackney_h3:await_response_loop/6` in `src/hackney_h3.erl` accumulates the HTTP/3 response body in memory without any size cap. The `after Timeout` clause is a per-message inactivity timer, not a wall-clock deadline: every received `stream_data` chunk, housekeeping `select` message, or `settings` frame resets it. A malicious HTTP/3 server that drips one small chunk every `Timeout - 1` ms with `Fin = false` and never terminates the stream keeps the loop alive indefinitely while the accumulation buffer grows without bound, eventually exhausting the BEAM process heap.\n\n### Details\n\nIn `src/hackney_h3.erl`, `await_response_loop/6` (line 430) builds the body with:\n\n```erlang\nNewBody = \u003c\u003cAccBody/binary, Data/binary\u003e\u003e\n```\n\nThere is no `max_body` check and no monotonic deadline. The `after Timeout` clause at line 463 is restarted on each loop iteration. A server that ensures at least one message arrives within `Timeout` ms indefinitely (one small chunk per interval is sufficient) prevents the timeout from firing while `AccBody` grows linearly. The same module's `wait_connected/3` (lines 388-389) shows the correct pattern: track an absolute start time and pass a shrinking `Remaining` budget into each `receive`. This loop does not.\n\n### Configurations\n\nOnly the HTTP/3 transport is affected. Applications using the default TCP/TLS hackney transport are not vulnerable. The vulnerability requires using `hackney_h3` directly or passing `{transport, h3}` to `hackney:request/5`.\n\n### PoC\n\n1. Stand up an HTTP/3 server that responds with `200 OK` headers (`Fin = false`), then emits a small `stream_data` chunk every `Timeout - margin` ms with `Fin = false` indefinitely.\n2. Issue `hackney:request(get, Url, [], \u003c\u003c\u003e\u003e, [{transport, h3}])` against it.\n3. Watch the client process heap grow monotonically. The configured timeout never fires; the process is eventually killed by `max_heap_size` or the OS OOM killer.\n\n### Impact\n\nRemote denial of service via unbounded memory consumption. Affects hackney 2.0.0 through 4.0.0 when using the HTTP/3 transport against an attacker-controlled or attacker-influenced server. Each affected request consumes unbounded memory until the BEAM is killed. CVSS v4.0: **8.2 (HIGH)**.\n\n## Resources\n\n* Introduction commit: https://github.com/benoitc/hackney/commit/0334af206d5099fdf510ed9eda18e34396f065ad\n* Patch commit: https://github.com/benoitc/hackney/commit/3d25f9fea26c90609de9d64366fedfe5065413bc","aliases":["CVE-2026-47077","EEF-CVE-2026-47077"],"modified":"2026-06-30T17:41:30.899031298Z","published":"2026-06-26T21:57:33Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-06-26T21:57:33Z","nvd_published_at":"2026-05-28T10:16:39Z","cwe_ids":["CWE-295","CWE-400"],"severity":"HIGH"},"references":[{"type":"WEB","url":"https://github.com/benoitc/hackney/security/advisories/GHSA-jq4m-q6p2-8gwc"},{"type":"WEB","url":"https://github.com/ex-aws/ex_aws_sns/security/advisories/GHSA-8jgf-23q5-x7xx"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-47077"},{"type":"WEB","url":"https://github.com/benoitc/hackney/commit/3d25f9fea26c90609de9d64366fedfe5065413bc"},{"type":"WEB","url":"https://cna.erlef.org/cves/CVE-2026-47077.html"},{"type":"PACKAGE","url":"https://github.com/benoitc/hackney"},{"type":"WEB","url":"https://osv.dev/vulnerability/EEF-CVE-2026-47077"}],"affected":[{"package":{"name":"hackney","ecosystem":"Hex","purl":"pkg:hex/hackney"},"ranges":[{"type":"SEMVER","events":[{"introduced":"2.0.0"},{"fixed":"4.0.1"}]}],"versions":["2.0.0","2.0.1","3.0.0","3.0.1","3.0.2","3.0.3","3.1.0","3.1.1","3.1.2","3.2.0","3.2.1","4.0.0"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-jq4m-q6p2-8gwc/GHSA-jq4m-q6p2-8gwc.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N"}]}