{"id":"EEF-CVE-2026-71397","summary":"Unbounded request body accumulation on streaming RPCs causes memory exhaustion in grpc_server","details":"## Summary\n\nAllocation 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.\n\n## Details\n\n**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.\n\n## Proof of concept\n\n1. 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`.\n\n## Impact\n\nAn unauthenticated client can crash a `grpc_server` node through one streaming RPC connection. This takes down every service on that node.\n\n## Configurations\n\nThe server must expose at least one client-streaming or bidirectional-streaming RPC method.","aliases":["CVE-2026-71397","GHSA-vx6q-cr5q-945g"],"modified":"2026-11-06T21:26:01.885531856Z","published":"2026-11-06T21:02:03.676Z","database_specific":{"capec_ids":["CAPEC-130"],"cpe_ids":["cpe:2.3:a:elixir-grpc:grpc_server:*:*:*:*:*:*:*:*"],"cwe_ids":["CWE-770"]},"references":[{"type":"ADVISORY","url":"https://github.com/elixir-grpc/grpc/security/advisories/GHSA-vx6q-cr5q-945g"},{"type":"WEB","url":"https://cna.erlef.org/cves/CVE-2026-71397.html"},{"type":"WEB","url":"https://github.com/elixir-grpc/grpc/commit/49e18c3ec6bb9afe2f712caad3dbab5c56a68a00"},{"type":"FIX","url":"https://github.com/elixir-grpc/grpc/commit/0b663ca53dbf0f36f7f67ff1d0026f4482a18915"},{"type":"PACKAGE","url":"https://hex.pm/packages/grpc_server"}],"affected":[{"package":{"name":"grpc_server","ecosystem":"Hex","purl":"pkg:hex/grpc_server"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.0.0"},{"fixed":"1.0.6"}]}],"versions":["1.0.0","1.0.1","1.0.2","1.0.3","1.0.4","1.0.5"],"database_specific":{"source":"https://cna.erlef.org/osv/EEF-CVE-2026-71397.json"}},{"ranges":[{"type":"GIT","repo":"https://github.com/elixir-grpc/grpc","events":[{"introduced":"49e18c3ec6bb9afe2f712caad3dbab5c56a68a00"},{"fixed":"0b663ca53dbf0f36f7f67ff1d0026f4482a18915"}]}],"versions":["v1.0.3","v1.0.0"],"database_specific":{"source":"https://cna.erlef.org/osv/EEF-CVE-2026-71397.json"}}],"schema_version":"1.9.2","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"}],"credits":[{"name":"Arpit Jain","type":"FINDER"},{"name":"Arpit Jain","type":"REPORTER"},{"name":"Arpit Jain","type":"REMEDIATION_DEVELOPER"},{"name":"Paulo Valente","type":"REMEDIATION_REVIEWER"},{"name":"Jonatan Männchen / EEF","type":"COORDINATOR"}]}