Aug 26, 2026·7 min read·5 visits
Unauthenticated remote attackers can crash Elixir-based gRPC servers by sending a small, highly compressed Gzip payload that expands to multiple gigabytes, triggering an Out-Of-Memory crash.
CVE-2026-53430 is a critical uncontrolled resource consumption vulnerability in the elixir-grpc/grpc library. An unauthenticated remote attacker can cause immediate memory exhaustion and system crashes by sending crafted gRPC frames compressed with Gzip, leading to a complete Denial of Service.
The elixir-grpc/grpc library is a widely used implementation of the gRPC protocol for the Elixir programming language, running on the Erlang Virtual Machine (BEAM). In versions prior to 1.0.0, the package exposes an unauthenticated attack surface through its default handling of Gzip-compressed messages. When a gRPC service endpoint receives an incoming HTTP/2 request with the grpc-encoding: gzip header, it processes the payload using the GRPC.Compressor.Gzip module to decompress the content.
This vulnerability is classified under CWE-409: Improper Handling of Highly Compressed Data (Data Amplification), commonly known as a Gzip decompression bomb. The bug is located in the decompression phase of the gRPC message pipeline, which operates prior to length validation. Because the framework does not check the output boundaries during the decompression phase, an unauthenticated remote attacker can trigger unbounded memory allocation, crashing the target server.
The impact of this flaw is a complete and immediate Denial of Service (DoS) of the affected Elixir application node. The vulnerability does not require valid credentials, session tokens, or any specific application-state prerequisites. Any gRPC service using the default Gzip compressor component is vulnerable to this attack vector.
The root cause of CVE-2026-53430 resides in the naive implementation of the decompress/1 function in lib/grpc/compressor/gzip.ex. This function accepts an incoming binary payload and passes it directly to Erlang's :zlib.gunzip/1 function. The :zlib.gunzip/1 function is a one-shot, non-incremental wrapper around the zlib library. It allocates the memory required to decompress the entire input stream in a single blocking operation.
This design allows for a significant data amplification ratio, where repetitive sequences compress highly efficiently. For example, a payload containing consecutive zero bytes can achieve a compression ratio of approximately 1032:1 under the DEFLATE algorithm. Under these conditions, an attacker can package a compressed block of multiple gigabytes into a transport payload of a few megabytes. When the BEAM node executes :zlib.gunzip/1, it attempts to allocate a continuous segment of heap memory large enough to hold the fully expanded, uncompressed output.
Standard gRPC protective measures like max_receive_message_length fail to prevent this exploitation. The gRPC protocol engine evaluates the incoming message size limits only after the binary payload has been fully decoded and decompressed. Because the decompression process occurs within the stateful compressor layer before the framework performs the length validation, the system consumes excessive physical memory and crashes before the framework can reject the oversized message.
In the vulnerable version of the library, the decompression code was written as a direct wrapper around Erlang's zlib module:
defmodule GRPC.Compressor.Gzip do
@behaviour GRPC.Compressor
def name, do: "gzip"
def compress(data) do
:zlib.gzip(data)
end
# VULNERABLE: Direct, unbounded decompression in a single step
def decompress(data) do
:zlib.gunzip(data)
end
endThe vulnerability is mitigated by replacing this single-pass decompression with an incremental, chunk-based decompression loop. The fix, implemented in commit 1afbab9d57d2a3e16ca9c62ffa4923338ea96cfc, processes the compressed payload in recursive 8 KB chunks and monitors the cumulative decompressed output size dynamically:
defmodule GRPC.Compressor.Gzip do
@behaviour GRPC.Compressor
# Enforces a 4 MB maximum limit by default
@default_max_decompressed_size 4 * 1024 * 1024
@input_chunk_size 8_192
def decompress(data) do
max_size = Application.get_env(:grpc, :max_decompressed_message_length, @default_max_decompressed_size)
z = :zlib.open()
# Window bits value of 31 configures zlib for gzip parsing
:ok = :zlib.inflateInit(z, 31)
try do
chunks = inflate_chunks(z, data, max_size, 0, [])
:zlib.inflateEnd(z)
IO.iodata_to_binary(chunks)
after
# Ensures resource cleanup to prevent port leaks
:zlib.close(z)
end
end
defp inflate_chunks(_z, <<>>, _max_size, _acc_size, acc), do: acc
defp inflate_chunks(z, data, max_size, acc_size, acc) do
{chunk, rest} = split_chunk(data)
output = :zlib.inflate(z, chunk)
new_size = acc_size + IO.iodata_length(output)
# Dynamic size verification checks limit before inflating the next chunk
if new_size > max_size do
raise GRPC.RPCError,
status: :resource_exhausted,
message: "Decompressed message exceeds limit of #{max_size} bytes"
end
inflate_chunks(z, rest, max_size, new_size, [acc, output])
end
defp split_chunk(data) when byte_size(data) <= @input_chunk_size, do: {data, <<>>}
defp split_chunk(<<chunk::bytes-size(@input_chunk_size), rest::binary>>), do: {chunk, rest}
endBy using the stateful :zlib.inflate/2 API, the patched version guarantees that memory allocation remains bounded. If the uncompressed output exceeds the preconfigured threshold, the function raises an exception and interrupts the operation, limiting resource utilization to the specified threshold.
An attacker can exploit this vulnerability by generating a highly compressed file consisting of repeated characters, typically zero bytes. The generation of a Gzip decompression bomb can be executed with standard command-line tools:
dd if=/dev/zero bs=1M count=4096 | gzip -9 > bomb.gzipThis command produces a compressed file of approximately 4 MB that decompresses into 4 GB of data. The attacker then encapsulates this file within a standard gRPC length-prefixed frame. This frame structure requires a 1-byte compression flag set to 1, a 4-byte big-endian field denoting the compressed size, and the compressed payload itself.
To complete the attack, the adversary initiates an HTTP/2 connection to the server and transmits the payload inside an HTTP/2 DATA frame. The companion HTTP/2 HEADERS frame must contain the grpc-encoding: gzip and content-type: application/grpc headers. Once received, the Cowboy handler passes the payload directly to the decompression function, exhausting system memory and causing the node to crash.
The security impact of CVE-2026-53430 is a severe Denial of Service. Because the Erlang Virtual Machine allocates memory dynamically on the process heap, an expansion of several gigabytes of data triggers a rapid exhaustion of system RAM. When the allocation exceeds the physical memory limits of the server host or container, the operating system kernel's Out-Of-Memory (OOM) killer intervenes and terminates the entire BEAM process immediately.
This termination results in the loss of all active connections, processing queues, and state within that VM instance. In clustered configurations, the loss of a node can cause cascade failures across remaining nodes if traffic is redirected without strict rate limiting. While Kubernetes or similar orchestrators may restart the terminated container automatically, an attacker can send decompression bombs continuously to keep the service in an ongoing crash loop.
The vulnerability is assessed with a CVSS 4.0 score of 8.7. The attack is executable entirely over the network, requires no system access privileges, demands no user interaction, and has low technical complexity. The subsequent impacts on data confidentiality and integrity are ranked as none, as the bug does not allow for arbitrary code execution or unauthorized read actions.
The primary remediation strategy is upgrading the Elixir gRPC dependencies to version 1.0.0 or later. Starting with version 1.0.0-rc.1, the library has been split into individual packages. Applications running a gRPC server must replace the legacy :grpc dependency with the new :grpc_server package inside their mix.exs configuration:
def deps do
[
{:grpc_server, "~> 1.0"},
{:protobuf, "~> 0.14"}
]
endIf an immediate upgrade is not feasible, administrators can apply network-level mitigations at the API gateway or load balancer layer. For instance, reverse proxies such as Envoy or NGINX can be configured to restrict the maximum allowed size of incoming HTTP/2 request bodies. Restricting the request size to a low threshold (e.g., 1 MB) reduces the maximum payload size an attacker can transmit, mitigating the severity of the amplification ratio.
Additionally, operations teams can configure the :max_decompressed_message_length parameter in their Elixir application configuration files to fine-tune the threshold. Setting this value to match application-specific limits prevents unnecessary memory allocation:
# Set the maximum allowed decompressed payload size to 2 MB
config :grpc, max_decompressed_message_length: 2 * 1024 * 1024CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
grpc elixir-grpc | >= 0.4.0, < 1.0.0 | 1.0.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-409 |
| Attack Vector | Network |
| CVSS 4.0 Score | 8.7 |
| EPSS Score | 0.00348 (0.35% exploitation probability) |
| Impact | Complete Denial of Service (OOM Crash) |
| Exploit Status | Proof-of-Concept Available |
| KEV Status | Not Listed |
The product does not limit or properly validate the size of highly compressed input data before or during decompression, enabling a dramatic amplification of data size in memory.
CVE-2026-55637 is a high-severity DNS rebinding vulnerability affecting the genieacs-mcp Model Context Protocol server. Prior to version 0.3.2, the application's Streamable HTTP transport lacks adequate Host and Origin header validation. This omission allows external attackers to bypass the Same-Origin Policy through a victim's browser and issue unauthenticated commands to loopback listeners.
A critical vulnerability exists in the elixir-grpc library's Erlpack codec, where the unsafe deserialization of Erlang External Term Format (ETF) payloads allows unauthenticated remote attackers to cause a Denial of Service through atom table exhaustion or execute arbitrary code on the host server.
An authorization bypass vulnerability exists in the elixir-grpc/grpc library version 0.8.0 up to 1.0.0. Due to insecure map merging precedence inside the HTTP-to-gRPC transcoding engine, query-string parameters and request bodies can override routing path variables, allowing attackers to execute unauthorized actions on other accounts.
An allocation of resources without limits or throttling vulnerability exists in the Elixir grpc server component when processing unary requests. Unauthenticated remote attackers can stream unbounded data payloads, bypassing standard timeout mechanisms and exhausting host BEAM VM memory, resulting in an immediate crash of the server node.
A cryptographic validation flaw (CWE-345) exists in the built-in SCTP implementation of mediasoup (NPM package < 3.20.6, Rust crate < 0.22.5). Due to missing cryptographic signature verification of State Cookies, an on-path attacker targeting PlainTransport or PipeTransport without DTLS can forge state cookies containing static magic bytes. This allows the attacker to establish arbitrary SCTP associations and inject malicious DataChannel messages.
An authentication bypass and account takeover vulnerability in the AshAuthentication Elixir library (developed by team-alembic) allows unauthenticated remote attackers to compromise local accounts. By relying on mutable and unverified email claims instead of stable cryptographic issuer and subject pairings during OAuth2 and OIDC federated login flows, the application fails to validate the trust boundary of the incoming session.