Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-48854

CVE-2026-48854: elixir-grpc DoS Vulnerability

CVE-2026-48854 is a denial of service vulnerability in elixir-grpc that allows attackers to exhaust server memory through uncontrolled resource allocation. This article covers technical details, affected versions, and mitigations.

Published:

CVE-2026-48854 Overview

CVE-2026-48854 is a resource exhaustion vulnerability in the elixir-grpc/grpc library that allows unauthenticated remote attackers to crash an Erlang BEAM virtual machine. The flaw resides in GRPC.Server.Adapters.Cowboy.Handler.read_full_body/3, which accumulates every received chunk into a single growing binary without any size cap. When a client omits the grpc-timeout header, the per-chunk read timeout resolves to :infinity, letting a slow-trickle client keep the connection alive while memory grows. A single TCP connection is enough to exhaust server memory and crash the node. The issue affects grpc versions from 0.3.1 up to (but not including) 1.0.0 and is categorized under CWE-770 (Allocation of Resources Without Limits or Throttling).

Critical Impact

A single unauthenticated request can exhaust BEAM memory and crash the entire Elixir node, causing a denial-of-service condition for all collocated gRPC services.

Affected Products

  • elixir-grpc grpc library, version 0.3.1
  • elixir-grpc grpc library, all versions up to and not including 1.0.0
  • Elixir/Erlang BEAM applications embedding the vulnerable gRPC server adapter

Discovery Timeline

  • 2026-06-15 - CVE-2026-48854 published to NVD
  • 2026-06-17 - Last updated in NVD database

Technical Details for CVE-2026-48854

Vulnerability Analysis

The vulnerability stems from unbounded memory allocation in the Cowboy adapter that handles gRPC unary requests. The read_full_body/3 function in lib/grpc/server/adapters/cowboy/handler.ex reads HTTP/2 DATA frames in chunks and concatenates each chunk into a single Erlang binary. No upper bound is enforced on the resulting binary, so an attacker controls how much memory the server allocates per request.

A second defect compounds the problem. The per-chunk read timeout derives from the grpc-timeout header sent by the client. When the header is absent, the timeout is set to :infinity. An attacker can therefore open one connection, slowly trickle bytes, and force the server to retain an ever-growing binary indefinitely. Because BEAM allocates large binaries on a shared heap, a single process can starve the entire VM.

Root Cause

The root cause is missing input validation against resource limits ([CWE-770]). The handler accepts arbitrary-sized request bodies and trusts client-supplied timeouts without a server-side ceiling. Neither a max_body_size option nor a default deadline existed prior to the fix.

Attack Vector

Exploitation requires only network reachability to the gRPC endpoint. The attacker sends a unary request with a large Content-Length or chunked DATA stream and omits the grpc-timeout header. The server allocates memory linearly with received bytes until the BEAM scheduler runs out of memory and the node terminates.

text
// Source: https://github.com/elixir-grpc/grpc/commit/49e18c3ec6bb9afe2f712caad3dbab5c56a68a00
// Patch: introduces a default 4 MB receive cap in handler.ex

   @default_trailers HTTP2.server_trailers()
   @trailers_flag 0b1000_0000

+  # 4 MB - matches gRPC-Go's default max receive message size.
+  # Override per-server with the :max_body_size option (bytes).
+  @default_max_body_size 4 * 1024 * 1024
+
   @type init_state :: {
           endpoint :: atom(),
           server :: {name :: String.t(), module()},

Detection Methods for CVE-2026-48854

Indicators of Compromise

  • Sudden growth of BEAM memory(:binary) or memory(:total) correlated with a single inbound HTTP/2 stream.
  • gRPC requests arriving without a grpc-timeout header from untrusted clients.
  • Long-lived HTTP/2 streams with low bytes-per-second throughput on gRPC ports.
  • Repeated OOM kills or erl_crash.dump files referencing the Cowboy handler process.

Detection Strategies

  • Monitor BEAM telemetry (:telemetry, recon, or observer_cli) for binary heap growth tied to individual Cowboy handler processes.
  • Inspect HTTP/2 access logs or reverse-proxy logs for requests missing grpc-timeout and large content-length values.
  • Alert on connections where elapsed time on a single stream exceeds a configured threshold without completion.

Monitoring Recommendations

  • Export Cowboy and Ranch metrics to a centralized observability stack and alert on per-process memory anomalies.
  • Track p99 request body size and request duration on gRPC endpoints; investigate sustained outliers.
  • Capture node-level OOM events and correlate with upstream IPs to identify probing attempts.

How to Mitigate CVE-2026-48854

Immediate Actions Required

  • Upgrade elixir-grpc/grpc to version 1.0.0 or later, which enforces a default 4 MB body cap.
  • Set an explicit :max_body_size value when starting endpoints to match application requirements.
  • Place a reverse proxy (for example, Envoy or NGINX) in front of the Elixir node to enforce request size and idle timeouts.
  • Reject inbound gRPC requests that omit a reasonable grpc-timeout header at the proxy layer.

Patch Information

The upstream fix is delivered in commit 49e18c3ec6bb9afe2f712caad3dbab5c56a68a00 and described in GHSA-q8gf-9rvj-gmgj. The patch introduces a :max_body_size option on start_endpoint/3 and a @default_max_body_size of 4 MB in the Cowboy handler, aligning with grpc-go defaults. Additional context is available in the CNA advisory and the OSV entry.

Workarounds

  • Terminate gRPC at an upstream proxy that enforces client_max_body_size and idle read timeouts.
  • Configure firewall or service mesh policies to drop unauthenticated traffic to gRPC ports.
  • Run the BEAM with strict memory limits (for example, container memory.max) so a single node failure does not cascade across replicas.
bash
# Configuration example - enforce body cap and adapter options after upgrade
# mix.exs
# {:grpc, "~> 1.0"}

# application.ex
GRPC.Server.start_endpoint(MyApp.Endpoint, 50051,
  adapter: GRPC.Server.Adapters.Cowboy,
  max_body_size: 4 * 1024 * 1024,
  adapter_opts: [
    idle_timeout: 30_000,
    request_timeout: 60_000
  ]
)

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.