{"containers":{"cna":{"affected":[{"collectionURL":"https://repo.hex.pm","cpes":["cpe:2.3:a:elixir-grpc:grpc_server:*:*:*:*:*:*:*:*"],"defaultStatus":"unaffected","modules":["'Elixir.GRPC.Server.Adapters.Cowboy.Handler'","'Elixir.GRPC.Server.Adapters.Cowboy'"],"packageName":"grpc_server","packageURL":"pkg:hex/grpc_server","product":"grpc_server","programFiles":["lib/grpc/server/adapters/cowboy/handler.ex","lib/grpc/server/adapters/cowboy.ex"],"programRoutines":[{"name":"'Elixir.GRPC.Server.Adapters.Cowboy.Handler':info/3"},{"name":"'Elixir.GRPC.Server.Adapters.Cowboy':reading_stream/1"}],"repo":"https://github.com/elixir-grpc/grpc","vendor":"elixir-grpc","versions":[{"lessThan":"1.0.6","status":"affected","version":"1.0.0","versionType":"semver"}]},{"collectionURL":"https://github.com","cpes":["cpe:2.3:a:elixir-grpc:grpc_server:*:*:*:*:*:*:*:*"],"defaultStatus":"unaffected","modules":["'Elixir.GRPC.Server.Adapters.Cowboy.Handler'","'Elixir.GRPC.Server.Adapters.Cowboy'"],"packageName":"elixir-grpc/grpc","packageURL":"pkg:github/elixir-grpc/grpc","product":"grpc_server","programFiles":["grpc_server/lib/grpc/server/adapters/cowboy/handler.ex","grpc_server/lib/grpc/server/adapters/cowboy.ex"],"programRoutines":[{"name":"'Elixir.GRPC.Server.Adapters.Cowboy.Handler':info/3"},{"name":"'Elixir.GRPC.Server.Adapters.Cowboy':reading_stream/1"}],"repo":"https://github.com/elixir-grpc/grpc","vendor":"elixir-grpc","versions":[{"lessThan":"0b663ca53dbf0f36f7f67ff1d0026f4482a18915","status":"affected","version":"49e18c3ec6bb9afe2f712caad3dbab5c56a68a00","versionType":"git"}]}],"configurations":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>The server must expose at least one client-streaming or bidirectional-streaming RPC method.</p>"},{"base64":false,"type":"text/markdown","value":"The server must expose at least one client-streaming or bidirectional-streaming RPC method."}],"value":"The server must expose at least one client-streaming or bidirectional-streaming RPC method."}],"cpeApplicability":[{"nodes":[{"cpeMatch":[{"criteria":"cpe:2.3:a:elixir-grpc:grpc_server:*:*:*:*:*:*:*:*","versionEndExcluding":"1.0.6","versionStartIncluding":"1.0.0","vulnerable":true}],"negate":false,"operator":"OR"}],"operator":"AND"}],"credits":[{"lang":"en","type":"finder","value":"Arpit Jain"},{"lang":"en","type":"reporter","value":"Arpit Jain"},{"lang":"en","type":"remediation developer","value":"Arpit Jain"},{"lang":"en","type":"remediation reviewer","value":"Paulo Valente"},{"lang":"en","type":"coordinator","value":"Jonatan Männchen / EEF"}],"descriptions":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>Allocation of Resources Without Limits or Throttling vulnerability in elixir-grpc grpc_server allows unauthenticated attackers to exhaust memory and crash the node via an oversized client-streaming or bidirectional-streaming request body.</p>\n<p>The streaming read clause of <code>'Elixir.GRPC.Server.Adapters.Cowboy.Handler':info/3</code> (<code>grpc_server/lib/grpc/server/adapters/cowboy/handler.ex</code>) never checks the configured <code>max_body_size</code>. Only the unary read path enforces that cap. <code>'Elixir.GRPC.Server.Adapters.Cowboy':reading_stream/1</code> (<code>grpc_server/lib/grpc/server/adapters/cowboy.ex</code>) appends every received chunk to its buffer until a complete length-prefixed message arrives. A client can declare a very large message and send it across many small HTTP/2 DATA frames, and the server buffers all of it.</p>\n<p>This issue affects grpc_server: from 1.0.0 before 1.0.6.</p>"},{"base64":false,"type":"text/markdown","value":"Allocation of Resources Without Limits or Throttling vulnerability in elixir-grpc grpc_server allows unauthenticated attackers to exhaust memory and crash the node via an oversized client-streaming or bidirectional-streaming request body.\n\nThe streaming read clause of `'Elixir.GRPC.Server.Adapters.Cowboy.Handler':info/3` (`grpc_server/lib/grpc/server/adapters/cowboy/handler.ex`) never checks the configured `max_body_size`. Only the unary read path enforces that cap. `'Elixir.GRPC.Server.Adapters.Cowboy':reading_stream/1` (`grpc_server/lib/grpc/server/adapters/cowboy.ex`) appends every received chunk to its buffer until a complete length-prefixed message arrives. A client can declare a very large message and send it across many small HTTP/2 DATA frames, and the server buffers all of it.\n\nThis issue affects grpc_server: from 1.0.0 before 1.0.6."}],"value":"Allocation of Resources Without Limits or Throttling vulnerability in elixir-grpc grpc_server allows unauthenticated attackers to exhaust memory and crash the node via an oversized client-streaming or bidirectional-streaming request body.\n\nThe streaming read clause of 'Elixir.GRPC.Server.Adapters.Cowboy.Handler':info/3 (grpc_server/lib/grpc/server/adapters/cowboy/handler.ex) never checks the configured max_body_size. Only the unary read path enforces that cap. 'Elixir.GRPC.Server.Adapters.Cowboy':reading_stream/1 (grpc_server/lib/grpc/server/adapters/cowboy.ex) appends every received chunk to its buffer until a complete length-prefixed message arrives. A client can declare a very large message and send it across many small HTTP/2 DATA frames, and the server buffers all of it.\n\nThis issue affects grpc_server: from 1.0.0 before 1.0.6."}],"impacts":[{"capecId":"CAPEC-130","descriptions":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>An unauthenticated client can crash a <code>grpc_server</code> node through one streaming RPC connection. This takes down every service on that node.</p>"},{"base64":false,"type":"text/markdown","value":"An unauthenticated client can crash a `grpc_server` node through one streaming RPC connection. This takes down every service on that node."}],"value":"An unauthenticated client can crash a grpc_server node through one streaming RPC connection. This takes down every service on 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-06T21:02:03.676Z","orgId":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","shortName":"EEF"},"references":[{"name":"Unbounded request body accumulation on streaming RPCs causes memory exhaustion in grpc_server","tags":["vendor-advisory","related"],"url":"https://github.com/elixir-grpc/grpc/security/advisories/GHSA-vx6q-cr5q-945g"},{"name":"EEF CNA record for CVE-2026-71397","tags":["related"],"url":"https://cna.erlef.org/cves/CVE-2026-71397.html"},{"name":"OSV record EEF-CVE-2026-71397","tags":["related"],"url":"https://osv.dev/vulnerability/EEF-CVE-2026-71397"},{"name":"Introducing commit 49e18c3 in elixir-grpc/grpc","tags":["related"],"url":"https://github.com/elixir-grpc/grpc/commit/49e18c3ec6bb9afe2f712caad3dbab5c56a68a00"},{"name":"Fix commit 0b663ca in elixir-grpc/grpc","tags":["patch"],"url":"https://github.com/elixir-grpc/grpc/commit/0b663ca53dbf0f36f7f67ff1d0026f4482a18915"}],"source":{"discovery":"EXTERNAL"},"title":"Unbounded request body accumulation on streaming RPCs causes memory exhaustion in grpc_server","x_proofOfConcept":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<ol>\n<li>Start a <code>grpc_server</code> endpoint that exposes a client-streaming or bidirectional-streaming RPC method.</li>\n<li>Open an HTTP/2 connection and send a request to that method.</li>\n<li>Send the request body across many small HTTP/2 DATA frames without <code>END_STREAM</code>, well past the configured <code>max_body_size</code>.</li>\n<li>Observe that the server buffers all of it and server memory grows. The equivalent unary call is rejected with <code>RESOURCE_EXHAUSTED</code>.</li>\n</ol>"},{"base64":false,"type":"text/markdown","value":"1. Start a `grpc_server` endpoint that exposes a client-streaming or bidirectional-streaming RPC method.\n2. Open an HTTP/2 connection and send a request to that method.\n3. Send the request body across many small HTTP/2 DATA frames without `END_STREAM`, well past the configured `max_body_size`.\n4. Observe that the server buffers all of it and server memory grows. The equivalent unary call is rejected with `RESOURCE_EXHAUSTED`."}],"value":"* Start a grpc_server endpoint that exposes a client-streaming or bidirectional-streaming RPC method.\n* Open an HTTP/2 connection and send a request to that method.\n* Send the request body across many small HTTP/2 DATA frames without END_STREAM, well past the configured max_body_size.\n* Observe that the server buffers all of it and server memory grows. The equivalent unary call is rejected with RESOURCE_EXHAUSTED."}],"x_technicalAnalysis":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p><strong>1. The cap applies to unary reads only</strong></p>\n<p>The commit that added <code>max_body_size</code> checks it in <code>read_full_body/4</code>, which serves unary requests through the <code>{:read_full_body, ref, pid}</code> clause of <code>'Elixir.GRPC.Server.Adapters.Cowboy.Handler':info/3</code>. The <code>{:read_body, ref, pid}</code> clause, which serves streaming requests, returns each chunk to the caller with no size check.</p>\n<p><strong>2. Unbounded buffering</strong></p>\n<p><code>'Elixir.GRPC.Server.Adapters.Cowboy':reading_stream/1</code> reads chunks through that clause and appends each one to a binary buffer. It emits a message only when <code>GRPC.Message.get_message/1</code> finds a complete length-prefixed gRPC message in the buffer. Until then, the buffer grows with every chunk.</p>\n<p><strong>3. Memory exhaustion</strong></p>\n<p>A client that declares a large message length and keeps sending DATA frames without <code>END_STREAM</code> makes the buffer grow without limit. The BEAM eventually runs out of memory and the node crashes.</p>"},{"base64":false,"type":"text/markdown","value":"**1. The cap applies to unary reads only**\n\nThe commit that added `max_body_size` checks it in `read_full_body/4`, which serves unary requests through the `{:read_full_body, ref, pid}` clause of `'Elixir.GRPC.Server.Adapters.Cowboy.Handler':info/3`. The `{:read_body, ref, pid}` clause, which serves streaming requests, returns each chunk to the caller with no size check.\n\n**2. Unbounded buffering**\n\n`'Elixir.GRPC.Server.Adapters.Cowboy':reading_stream/1` reads chunks through that clause and appends each one to a binary buffer. It emits a message only when `GRPC.Message.get_message/1` finds a complete length-prefixed gRPC message in the buffer. Until then, the buffer grows with every chunk.\n\n**3. Memory exhaustion**\n\nA client that declares a large message length and keeps sending DATA frames without `END_STREAM` makes the buffer grow without limit. The BEAM eventually runs out of memory and the node crashes."}],"value":"1. The cap applies to unary reads only\n\nThe commit that added max_body_size checks it in read_full_body/4, which serves unary requests through the {:read_full_body, ref, pid} clause of 'Elixir.GRPC.Server.Adapters.Cowboy.Handler':info/3. The {:read_body, ref, pid} clause, which serves streaming requests, returns each chunk to the caller with no size check.\n\n2. Unbounded buffering\n\n'Elixir.GRPC.Server.Adapters.Cowboy':reading_stream/1 reads chunks through that clause and appends each one to a binary buffer. It emits a message only when GRPC.Message.get_message/1 finds a complete length-prefixed gRPC message in the buffer. Until then, the buffer grows with every chunk.\n\n3. Memory exhaustion\n\nA client that declares a large message length and keeps sending DATA frames without END_STREAM makes the buffer grow without limit. The BEAM eventually runs out of memory and the node crashes."}]}},"cveMetadata":{"assignerOrgId":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","assignerShortName":"EEF","cveId":"CVE-2026-71397","datePublished":"2026-11-06T21:02:03.676Z","dateReserved":"2026-08-19T10:30:01.929Z","dateUpdated":"2026-11-06T21:02:03.676Z","state":"PUBLISHED"},"dataType":"CVE_RECORD","dataVersion":"5.2"}