{"containers":{"cna":{"affected":[{"collectionURL":"https://repo.hex.pm","cpes":["cpe:2.3:a:ninenines:cowboy:*:*:*:*:*:*:*:*"],"defaultStatus":"unaffected","modules":["cowboy_http"],"packageName":"cowboy","packageURL":"pkg:hex/cowboy","product":"cowboy","programFiles":["src/cowboy_http.erl"],"programRoutines":[{"name":"cowboy_http:parse/2"},{"name":"cowboy_http:loop/1"}],"repo":"https://github.com/ninenines/cowboy","vendor":"ninenines","versions":[{"lessThan":"*","status":"affected","version":"2.18.0","versionType":"semver"}]},{"collectionURL":"https://github.com","cpes":["cpe:2.3:a:ninenines:cowboy:*:*:*:*:*:*:*:*"],"defaultStatus":"unaffected","modules":["cowboy_http"],"packageName":"ninenines/cowboy","packageURL":"pkg:github/ninenines/cowboy","product":"cowboy","programFiles":["src/cowboy_http.erl"],"programRoutines":[{"name":"cowboy_http:parse/2"},{"name":"cowboy_http:loop/1"}],"repo":"https://github.com/ninenines/cowboy","vendor":"ninenines","versions":[{"lessThan":"3a630c07e1521abf63a1b9ea080509aa1337b60d","status":"affected","version":"faf5594fbf74530ace90b0c46c936bdc2cf82081","versionType":"git"}]}],"configurations":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>The amount of data buffered scales with how long the current handler keeps the connection busy. Any HTTP/1.1 endpoint exposes a window, but deployments with handlers that hold a request open, such as long polling with <code>cowboy_loop</code>, streamed responses via <code>cowboy_req:stream_reply/3</code>, or slow backend calls, give an attacker the time to buffer significant memory. HTTP/2 connections are not affected.</p>"},{"base64":false,"type":"text/markdown","value":"The amount of data buffered scales with how long the current handler keeps the connection busy. Any HTTP/1.1 endpoint exposes a window, but deployments with handlers that hold a request open, such as long polling with `cowboy_loop`, streamed responses via `cowboy_req:stream_reply/3`, or slow backend calls, give an attacker the time to buffer significant memory. HTTP/2 connections are not affected."}],"value":"The amount of data buffered scales with how long the current handler keeps the connection busy. Any HTTP/1.1 endpoint exposes a window, but deployments with handlers that hold a request open, such as long polling with cowboy_loop, streamed responses via cowboy_req:stream_reply/3, or slow backend calls, give an attacker the time to buffer significant memory. HTTP/2 connections are not affected."}],"cpeApplicability":[{"nodes":[{"cpeMatch":[{"criteria":"cpe:2.3:a:ninenines:cowboy:*:*:*:*:*:*:*:*","versionStartIncluding":"2.18.0","vulnerable":true}],"negate":false,"operator":"OR"}],"operator":"AND"}],"credits":[{"lang":"en","type":"finder","value":"Mikica Ivosevic"},{"lang":"en","type":"reporter","value":"Mikica Ivosevic"},{"lang":"en","type":"coordinator","value":"Jonatan Männchen / EEF"}],"dateAssigned":"2026-10-26T10:41:07.000Z","descriptions":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>Allocation of Resources Without Limits or Throttling vulnerability in ninenines cowboy allows an unauthenticated remote attacker to exhaust connection process memory over HTTP/1.1.</p>\n<p>Once a request has been received in full and its handler is still running, <code>cowboy_http:parse/2</code> in <code>src/cowboy_http.erl</code> appends every further byte that arrives on the keep-alive connection to the connection buffer and returns to the receive loop without parsing it. The socket stays in active mode and no limit applies to this buffer: <code>max_request_line_length</code>, <code>max_headers</code> and the other parser limits only take effect once the handler returns and parsing resumes, and the only timer in this state is <code>idle_timeout</code> (default 60 seconds), which is reset on every received chunk. A client can therefore send an arbitrary amount of data on one connection for as long as the handler runs, and a few connections to an endpoint that holds requests open can drive the Erlang VM into out-of-memory conditions.</p>\n<p>This issue affects cowboy: from 2.18.0 onward.</p>"},{"base64":false,"type":"text/markdown","value":"Allocation of Resources Without Limits or Throttling vulnerability in ninenines cowboy allows an unauthenticated remote attacker to exhaust connection process memory over HTTP/1.1.\n\nOnce a request has been received in full and its handler is still running, `cowboy_http:parse/2` in `src/cowboy_http.erl` appends every further byte that arrives on the keep-alive connection to the connection buffer and returns to the receive loop without parsing it. The socket stays in active mode and no limit applies to this buffer: `max_request_line_length`, `max_headers` and the other parser limits only take effect once the handler returns and parsing resumes, and the only timer in this state is `idle_timeout` (default 60 seconds), which is reset on every received chunk. A client can therefore send an arbitrary amount of data on one connection for as long as the handler runs, and a few connections to an endpoint that holds requests open can drive the Erlang VM into out-of-memory conditions.\n\nThis issue affects cowboy: from 2.18.0 onward."}],"value":"Allocation of Resources Without Limits or Throttling vulnerability in ninenines cowboy allows an unauthenticated remote attacker to exhaust connection process memory over HTTP/1.1.\n\nOnce a request has been received in full and its handler is still running, cowboy_http:parse/2 in src/cowboy_http.erl appends every further byte that arrives on the keep-alive connection to the connection buffer and returns to the receive loop without parsing it. The socket stays in active mode and no limit applies to this buffer: max_request_line_length, max_headers and the other parser limits only take effect once the handler returns and parsing resumes, and the only timer in this state is idle_timeout (default 60 seconds), which is reset on every received chunk. A client can therefore send an arbitrary amount of data on one connection for as long as the handler runs, and a few connections to an endpoint that holds requests open can drive the Erlang VM into out-of-memory conditions.\n\nThis issue affects cowboy: from 2.18.0 onward."}],"impacts":[{"capecId":"CAPEC-130","descriptions":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>An unauthenticated remote client can make one connection process hold an arbitrary amount of memory by sending data after a request while its handler runs. A few such connections to an endpoint that holds requests open exhaust node memory and terminate every connection served by that node.</p>"},{"base64":false,"type":"text/markdown","value":"An unauthenticated remote client can make one connection process hold an arbitrary amount of memory by sending data after a request while its handler runs. A few such connections to an endpoint that holds requests open exhaust node memory and terminate every connection served by that node."}],"value":"An unauthenticated remote client can make one connection process hold an arbitrary amount of memory by sending data after a request while its handler runs. A few such connections to an endpoint that holds requests open exhaust node memory and terminate every connection served by that node."}]}],"metrics":[{"cvssV4_0":{"Automatable":"NOT_DEFINED","Recovery":"NOT_DEFINED","Safety":"NOT_DEFINED","attackComplexity":"LOW","attackRequirements":"PRESENT","attackVector":"NETWORK","baseScore":8.2,"baseSeverity":"HIGH","privilegesRequired":"NONE","providerUrgency":"NOT_DEFINED","subAvailabilityImpact":"NONE","subConfidentialityImpact":"NONE","subIntegrityImpact":"NONE","userInteraction":"NONE","valueDensity":"NOT_DEFINED","vectorString":"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","version":"4.0","vulnAvailabilityImpact":"HIGH","vulnConfidentialityImpact":"NONE","vulnIntegrityImpact":"NONE","vulnerabilityResponseEffort":"NOT_DEFINED"},"format":"CVSS","scenarios":[{"lang":"en","value":"GENERAL"}]}],"problemTypes":[{"descriptions":[{"cweId":"CWE-770","description":"CWE-770 Allocation of Resources Without Limits or Throttling","lang":"en","type":"CWE"}]}],"providerMetadata":{"dateUpdated":"2026-11-06T10:29:00.314Z","orgId":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","shortName":"EEF"},"references":[{"name":"EEF CNA record for CVE-2026-115701","tags":["related","third-party-advisory"],"url":"https://cna.erlef.org/cves/CVE-2026-115701.html"},{"name":"OSV record EEF-CVE-2026-115701","tags":["related"],"url":"https://osv.dev/vulnerability/EEF-CVE-2026-115701"},{"name":"Introducing commit faf5594 in ninenines/cowboy","tags":["related"],"url":"https://github.com/ninenines/cowboy/commit/faf5594fbf74530ace90b0c46c936bdc2cf82081"},{"name":"Fix commit 3a630c0 in ninenines/cowboy","tags":["patch"],"url":"https://github.com/ninenines/cowboy/commit/3a630c07e1521abf63a1b9ea080509aa1337b60d"}],"source":{"discovery":"EXTERNAL"},"title":"Cowboy HTTP/1.1 Unbounded Buffering of Pipelined Data During Request Handling Enables Memory Exhaustion","x_gcve":[{"recordType":"advisory","vulnId":"CVE-2026-115701"}],"x_proofOfConcept":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<ol>\n<li>Start a cowboy HTTP/1.1 listener with a handler that takes time to reply, for example one that sleeps 20 seconds before calling <code>cowboy_req:reply/4</code>.</li>\n<li>Open one TCP connection and send a complete <code>GET / HTTP/1.1</code> request with a <code>Host</code> header.</li>\n<li>While the handler is still running, keep writing arbitrary bytes on the same connection, for example 300 one-megabyte chunks.</li>\n<li>Inspect the connection process with <code>erlang:process_info/2</code> while the handler runs: its referenced binaries grow by the amount sent and <code>erlang:memory(binary)</code> rises by the same amount. No parser limit or timeout interrupts the transfer.</li>\n<li>When the handler replies, the client still receives the <code>200 OK</code>; only afterwards does the buffered data get parsed and rejected.</li>\n</ol>\n<p>On 2.16.1 and 2.17.0 step 3 is cut short: the server answers <code>414 Request-URI Too Long</code> with <code>connection: close</code> as soon as the first chunk arrives and holds nothing.</p>"},{"base64":false,"type":"text/markdown","value":"1. Start a cowboy HTTP/1.1 listener with a handler that takes time to reply, for example one that sleeps 20 seconds before calling `cowboy_req:reply/4`.\n2. Open one TCP connection and send a complete `GET / HTTP/1.1` request with a `Host` header.\n3. While the handler is still running, keep writing arbitrary bytes on the same connection, for example 300 one-megabyte chunks.\n4. Inspect the connection process with `erlang:process_info/2` while the handler runs: its referenced binaries grow by the amount sent and `erlang:memory(binary)` rises by the same amount. No parser limit or timeout interrupts the transfer.\n5. When the handler replies, the client still receives the `200 OK`; only afterwards does the buffered data get parsed and rejected.\n\nOn 2.16.1 and 2.17.0 step 3 is cut short: the server answers `414 Request-URI Too Long` with `connection: close` as soon as the first chunk arrives and holds nothing."}],"value":"* Start a cowboy HTTP/1.1 listener with a handler that takes time to reply, for example one that sleeps 20 seconds before calling cowboy_req:reply/4.\n* Open one TCP connection and send a complete GET / HTTP/1.1 request with a Host header.\n* While the handler is still running, keep writing arbitrary bytes on the same connection, for example 300 one-megabyte chunks.\n* Inspect the connection process with erlang:process_info/2 while the handler runs: its referenced binaries grow by the amount sent and erlang:memory(binary) rises by the same amount. No parser limit or timeout interrupts the transfer.\n* When the handler replies, the client still receives the 200 OK; only afterwards does the buffered data get parsed and rejected.\n\nOn 2.16.1 and 2.17.0 step 3 is cut short: the server answers 414 Request-URI Too Long with connection: close as soon as the first chunk arrives and holds nothing."}],"x_technicalAnalysis":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p><strong>1. Request completes, handler runs.</strong> When <code>cowboy_http</code> finishes reading a request it moves the parser to the <code>ps_next_request</code> state while the stream for that request is still alive. The connection process keeps the socket in active mode (<code>setopts_active/1</code> re-arms <code>{active, N}</code> whenever a passive notification arrives), so the VM continues to deliver socket data to the process.</p>\n<p><strong>2. Data is appended, never parsed.</strong> Each incoming chunk reaches <code>loop/1</code>, which concatenates it onto the connection buffer and calls <code>parse/2</code>. The <code>parse/2</code> clause for <code>in_state=ps_next_request</code> with a live <code>#stream{}</code> returns straight to <code>before_loop/1</code> with the enlarged buffer, deferring all parsing until the current stream stops. The parser limits (<code>max_request_line_length</code>, <code>max_header_name_length</code>, <code>max_header_value_length</code>, <code>max_headers</code>) are enforced only by the parsing clauses that run after that point, and <code>max_skip_body_length</code> only covers an unread body of the current request, not bytes after it.</p>\n<p><strong>3. No timer bounds the window.</strong> While a stream is live the connection runs on <code>idle_timeout</code> (default 60 seconds), and <code>set_timeout/2</code> resets it on every received chunk. The attacker therefore keeps the window open by continuing to send. Only the handler finishing ends it, at which point parsing resumes, the buffered bytes fail the request-line checks, and the connection closes with a 4xx response. By then the data has been held for the full handler duration.</p>\n<p><strong>4. Introduction.</strong> The behaviour arrived with the change that removed concurrent processing of pipelined HTTP/1.1 requests (first shipped in 2.18.0). Earlier releases parsed pipelined data as it arrived, so excess bytes hit the request-line limit immediately and the connection was closed with <code>414 Request-URI Too Long</code> before any significant amount was buffered. The introducing commit describes the intended behaviour as stopping reads from the socket until the stream stops, but the code keeps the socket active and buffers instead.</p>"},{"base64":false,"type":"text/markdown","value":"**1. Request completes, handler runs.** When `cowboy_http` finishes reading a request it moves the parser to the `ps_next_request` state while the stream for that request is still alive. The connection process keeps the socket in active mode (`setopts_active/1` re-arms `{active, N}` whenever a passive notification arrives), so the VM continues to deliver socket data to the process.\n\n**2. Data is appended, never parsed.** Each incoming chunk reaches `loop/1`, which concatenates it onto the connection buffer and calls `parse/2`. The `parse/2` clause for `in_state=ps_next_request` with a live `#stream{}` returns straight to `before_loop/1` with the enlarged buffer, deferring all parsing until the current stream stops. The parser limits (`max_request_line_length`, `max_header_name_length`, `max_header_value_length`, `max_headers`) are enforced only by the parsing clauses that run after that point, and `max_skip_body_length` only covers an unread body of the current request, not bytes after it.\n\n**3. No timer bounds the window.** While a stream is live the connection runs on `idle_timeout` (default 60 seconds), and `set_timeout/2` resets it on every received chunk. The attacker therefore keeps the window open by continuing to send. Only the handler finishing ends it, at which point parsing resumes, the buffered bytes fail the request-line checks, and the connection closes with a 4xx response. By then the data has been held for the full handler duration.\n\n**4. Introduction.** The behaviour arrived with the change that removed concurrent processing of pipelined HTTP/1.1 requests (first shipped in 2.18.0). Earlier releases parsed pipelined data as it arrived, so excess bytes hit the request-line limit immediately and the connection was closed with `414 Request-URI Too Long` before any significant amount was buffered. The introducing commit describes the intended behaviour as stopping reads from the socket until the stream stops, but the code keeps the socket active and buffers instead."}],"value":"1. Request completes, handler runs. When cowboy_http finishes reading a request it moves the parser to the ps_next_request state while the stream for that request is still alive. The connection process keeps the socket in active mode (setopts_active/1 re-arms {active, N} whenever a passive notification arrives), so the VM continues to deliver socket data to the process.\n\n2. Data is appended, never parsed. Each incoming chunk reaches loop/1, which concatenates it onto the connection buffer and calls parse/2. The parse/2 clause for in_state=ps_next_request with a live #stream{} returns straight to before_loop/1 with the enlarged buffer, deferring all parsing until the current stream stops. The parser limits (max_request_line_length, max_header_name_length, max_header_value_length, max_headers) are enforced only by the parsing clauses that run after that point, and max_skip_body_length only covers an unread body of the current request, not bytes after it.\n\n3. No timer bounds the window. While a stream is live the connection runs on idle_timeout (default 60 seconds), and set_timeout/2 resets it on every received chunk. The attacker therefore keeps the window open by continuing to send. Only the handler finishing ends it, at which point parsing resumes, the buffered bytes fail the request-line checks, and the connection closes with a 4xx response. By then the data has been held for the full handler duration.\n\n4. Introduction. The behaviour arrived with the change that removed concurrent processing of pipelined HTTP/1.1 requests (first shipped in 2.18.0). Earlier releases parsed pipelined data as it arrived, so excess bytes hit the request-line limit immediately and the connection was closed with 414 Request-URI Too Long before any significant amount was buffered. The introducing commit describes the intended behaviour as stopping reads from the socket until the stream stops, but the code keeps the socket active and buffers instead."}]}},"cveMetadata":{"assignerOrgId":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","assignerShortName":"EEF","cveId":"CVE-2026-115701","datePublished":"2026-11-06T10:29:00.314Z","dateReserved":"2026-10-26T10:30:01.636Z","dateUpdated":"2026-11-06T10:29:00.314Z","state":"PUBLISHED"},"dataType":"CVE_RECORD","dataVersion":"5.2","x_gcve":[{"extensions":{"bcp-05-x-01":{"ai_annotations":[{"ai_level":"generated","description":"VLAI severity classification was generated by Vulnerability-Lookup's /vlai/severity-classification API endpoint based on vulnerability description text.","field_name":"x_gcve.extensions.vlai-severity-enrichment","models":[{"gna_source":1,"identifier":"vlai-severity-classification","name":"VLAI Severity","provider":"CIRCL","version":"fc530b2263ef5a89ae4c75ffcbf6b4d878d44b94"}],"review_status":"none","scope":"field","tags":["ai-computer-assisted:assistance-level=\"ai-generated\"","ai-computer-assisted:review-level=\"unreviewed\""]}]},"vlai-severity-enrichment":{"confidence":0.9684267044067384,"generated_at":"2026-11-06T11:30:06+00:00","severity":"High","vulnerability_id":"CVE-2026-115701"}}}]}