Am I affected?

type your grpc version to check

Description

Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in elixir-grpc grpc_core and grpc allows unauthenticated attackers to exhaust server memory via a compressed Erlang external term in a gRPC message body.

GRPC.Codec.Erlpack.decode/2 (grpc_core/lib/grpc/codec/erlpack.ex, and lib/grpc/codec/erlpack.ex before the package split) passes the message body to :erlang.binary_to_term/2. That function inflates a compressed term in full before it returns. The codec sets no limit on the decoded size, and its type checks run only on the decoded term. The server's max_body_size limit counts the compressed bytes of the request. A request with Content-Type: application/grpc+erlpack can therefore make the server allocate a term much larger than the request body.

This issue affects grpc: from 0.4.0 before 1.0.0; grpc_core: from 1.0.0 before 1.1.0.

Technical analysis

1. Codec selection

The server selects the codec from the request Content-Type. application/grpc+erlpack selects GRPC.Codec.Erlpack when the server registers it. No authentication step comes before this.

2. Size limit on compressed bytes only

The server limits the request body with max_body_size, which counts the bytes received. With the gRPC compressed flag set to 0, the transport decompression limit does not apply, and the message reaches the codec unchanged.

3. Expansion inside binary_to_term/2

GRPC.Codec.Erlpack.decode/2 calls :erlang.binary_to_term(binary, [:safe]). The Erlang external term format has a compressed form (version byte 131, tag 80, a 32-bit uncompressed size, then a zlib stream). binary_to_term/2 inflates it in full, and the :safe option does not limit the size. ensure_safe_term!/1 runs after the call returns and accepts a large binary.

4. Result

In a test against grpc_server 1.0.6, a 260,932-byte request body decoded to a 268,435,456-byte binary, which the server passed to the application callback.

Proof of concept

  1. Start a gRPC server that registers GRPC.Codec.Erlpack in its codecs list.
  2. Build the payload with :erlang.term_to_binary(:binary.copy(<<0>>, 268_435_456), [:compressed]). The result is 260,932 bytes.
  3. Send the payload as one uncompressed gRPC message (compressed flag 0) to any method of the server, with Content-Type: application/grpc+erlpack.
  4. Observe that the server allocates the 268,435,456-byte binary and passes it to the application callback.

Weaknesses & attack patterns

Weakness

CWE-409 · Improper Handling of Highly Compressed Data (Data Amplification) in catalog → MITRE ↗

Attack patterns

CAPEC-130 · Excessive Allocation MITRE ↗

An unauthenticated client can make a server that registers the Erlpack codec allocate memory far beyond the size of the request with one request. Memory exhaustion affects every service on that node.

Affected — Hex / grpc Hex.pm ↗ Repository ↗

≥ 0.4.0 < 1.0.0 affected
every other version: unaffected
cpe cpe:2.3:a:elixir-grpc:grpc:*:*:*:*:*:*:*:*
version type semver
modules · source files · routines
modules 'Elixir.GRPC.Codec.Erlpack'
source files lib/grpc/codec/erlpack.ex
routines 'Elixir.GRPC.Codec.Erlpack':decode/2

Affected — GitHub / elixir-grpc/grpc Repository ↗

≥ 25bcc56 < 0332faa affected
every other version: unaffected
cpe cpe:2.3:a:elixir-grpc:grpc:*:*:*:*:*:*:*:*
version type git
modules · source files · routines
modules 'Elixir.GRPC.Codec.Erlpack'
source files lib/grpc/codec/erlpack.ex
routines 'Elixir.GRPC.Codec.Erlpack':decode/2

Affected — Hex / grpc_core Hex.pm ↗ Repository ↗

≥ 1.0.0 < 1.1.0 affected
every other version: unaffected
cpe cpe:2.3:a:elixir-grpc:grpc_core:*:*:*:*:*:*:*:*
version type semver
modules · source files · routines
modules 'Elixir.GRPC.Codec.Erlpack'
source files lib/grpc/codec/erlpack.ex
routines 'Elixir.GRPC.Codec.Erlpack':decode/2

Affected — GitHub / elixir-grpc/grpc Repository ↗

≥ 0332faa < d6bc56a affected
every other version: unaffected
cpe cpe:2.3:a:elixir-grpc:grpc_core:*:*:*:*:*:*:*:*
version type git
modules · source files · routines
modules 'Elixir.GRPC.Codec.Erlpack'
source files grpc_core/lib/grpc/codec/erlpack.ex
routines 'Elixir.GRPC.Codec.Erlpack':decode/2

Workarounds

Remove GRPC.Codec.Erlpack from the server's codecs list if the codec is not needed.

If the codec is needed, register a wrapper codec in its place. The wrapper implements the GRPC.Codec behaviour, returns "erlpack" from name/0, raises in decode/2 when the body starts with the bytes 131, 80 (the compressed term tag), and delegates all other calls to GRPC.Codec.Erlpack.

Configurations

GRPC.Codec.Erlpack must be explicitly registered as a codec on the gRPC server.

References

Credits

Jace Reporter
zx Finder Reporter
Jiacheng Zhong Finder
Zhun Wang Finder
Junmin Zhu Finder
Hongwei Li Finder Reporter
Han Dai Finder
Suyue Guo Finder
Songyang Peng Finder
Ziyue Pan Finder
Paulo Valente Remediation developer
Jonatan Männchen / EEF Coordinator
Peter Ullrich Coordinator

CVSS breakdown

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
« All CVEs