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

CVE-2026-54890: Erlang OTP Integer Underflow DOS Vulnerability

CVE-2026-54890 is an integer underflow flaw in Erlang OTP that causes VM-level crashes through excessive memory allocation. This article covers the technical details, affected versions, impact, and mitigation strategies.

Published:

CVE-2026-54890 Overview

CVE-2026-54890 is an integer underflow vulnerability [CWE-191] in the Erlang/OTP External Term Format (ETF) decoder. The BIT_BINARY_EXT tag (77) handler in erts/emulator/beam/external.c accepts an encoding with both length and trailing-bits fields set to zero. Subsequent bitstring size arithmetic underflows an unsigned integer, yielding a value near 2^64 that is passed to the memory allocator. The allocator aborts the entire Erlang node with a fatal message. Any application that decodes ETF from untrusted sources through binary_to_term/1,2 or enif_binary_to_term() is exposed.

Critical Impact

A single malformed ETF payload triggers a VM-level abort that supervision trees, try/catch, and the [safe] option cannot intercept, causing full-node denial of service.

Affected Products

  • Erlang/OTP 27.0 through versions before 29.0.4
  • Erlang/OTP 28.5.0.4 and 27.3.4.15 (fixed releases on maintenance branches)
  • erts runtime system 15.0 through before 17.0.4, 16.4.0.4, and 15.2.7.11

Discovery Timeline

  • 2026-07-27 - CVE-2026-54890 published to NVD
  • 2026-07-30 - Last updated in NVD database

Technical Details for CVE-2026-54890

Vulnerability Analysis

The defect resides in the ETF decoder path that processes BIT_BINARY_EXT (tag 77) terms. This tag encodes an Erlang bitstring using a byte length plus a trailing-bits count that indicates how many bits in the final byte are significant. The decoder computes the total bit size as (length * 8) - (8 - trailing_bits) using unsigned arithmetic. When an attacker submits a payload with length = 0 and trailing_bits = 0, the expression evaluates to 0 - 8 and wraps to approximately 2^64.

The wrapped value is then passed as an allocation size for a binary buffer. The runtime cannot satisfy the request and aborts with a message such as Cannot allocate 2305843009213693951 bytes of memory (of type binary). The failure occurs inside the emulator itself, not inside a scheduled Erlang process.

Because the abort happens at the C runtime layer, it bypasses every Erlang-level safety mechanism. Supervision trees cannot restart the crashed component. A try/catch around binary_to_term/1 never runs its handler. The [safe] option to binary_to_term/2 only restricts atom creation and does not perform structural validation of binary encodings.

Root Cause

The root cause is missing input validation on the BIT_BINARY_EXT fields combined with unsigned integer arithmetic that underflows without checks. Both length == 0 and trailing_bits == 0 should be rejected as structurally invalid before size computation.

Attack Vector

Any endpoint that calls binary_to_term/1, binary_to_term/2, or the NIF enif_binary_to_term() on network-attacker-controlled input is exposed. Message queues, HTTP handlers, and RPC endpoints that accept ETF payloads can be crashed by a small crafted binary. The Erlang distribution protocol shares the same decoder path, but distribution is expected to run on trusted networks per the OTP Secure Coding Guidelines (DSG-011).

c
                if (ep[-1] == BIT_BINARY_EXT) {
                    Uint trailing_bits = ep[4];

-                   if (((trailing_bits == 0) != (nu == 0)) ||
-                       trailing_bits > 8) {
+                   /* We accept a trailing bit count of 8 for backwards
+                    * compatibility reasons, even though it's not the most
+                    * compact representation. */
+                   if (trailing_bits < 1 ||
+                       trailing_bits > 8 ||
+                       size_in_bits < 8) {
                        goto error;
                    }

Source: Erlang/OTP commit dc1bf9344c0ce62717cf60866590cea0242780fd. The patch tightens validation by rejecting trailing_bits outside the range 1-8 and requiring size_in_bits to be at least 8, eliminating the underflow condition.

Detection Methods for CVE-2026-54890

Indicators of Compromise

  • Sudden abnormal termination of an Erlang node with a memory allocator abort message referencing an allocation of approximately 2305843009213693951 bytes of type binary.
  • erl_crash.dump files created on hosts running Erlang/OTP 27.0 through 29.0.3 that reference the ETF decoder.
  • Repeated inbound requests carrying ETF payloads with BIT_BINARY_EXT (byte value 77) followed by four zero length bytes and a zero trailing-bits byte.

Detection Strategies

  • Monitor supervisor restart telemetry and process managers (systemd, Kubernetes) for repeated Erlang node exits without corresponding application-level exceptions.
  • Inspect application logs for the allocator abort string; VM-level aborts do not produce standard Erlang stack traces.
  • Deploy network inspection or WAF rules on services that ingest ETF (for example, RabbitMQ, CouchDB, ejabberd, EMQX) to flag BIT_BINARY_EXT frames with zero-valued size fields.

Monitoring Recommendations

  • Alert on unexpected beam.smp process exits and correlate with inbound traffic captured at the same timestamp.
  • Track the deployed erts version across the fleet and flag any host running an unpatched release from the affected ranges.
  • Enable audit logging on any code path that calls binary_to_term/1,2 or enif_binary_to_term() against externally sourced data.

How to Mitigate CVE-2026-54890

Immediate Actions Required

  • Upgrade to Erlang/OTP 29.0.4, 28.5.0.4, or 27.3.4.15, corresponding to erts 17.0.4, 16.4.0.4, or 15.2.7.11 respectively.
  • Inventory all applications that call binary_to_term/1,2 or enif_binary_to_term() on data sourced from untrusted networks and prioritize them for patching.
  • Restrict exposure of ETF-consuming endpoints to trusted networks until the runtime is upgraded.

Patch Information

The fix is committed in the Erlang/OTP repository as dc1bf9344c0ce62717cf60866590cea0242780fd and released in OTP 29.0.4, 28.5.0.4, and 27.3.4.15. Details are published in the GitHub Security Advisory GHSA-54pw-5645-jh86 and the Erlang Ecosystem Foundation CNA record.

Workarounds

  • Wrap ETF-decoding endpoints with a proxy or protocol filter that rejects BIT_BINARY_EXT payloads with a zero length or zero trailing-bits field.
  • Replace binary_to_term/1,2 on untrusted input with a strict, application-defined codec (for example, JSON with a validating schema) until the patched runtime is deployed.
  • Enforce the OTP Secure Coding Guideline DSG-011 by ensuring Erlang distribution runs only across trusted network segments.
bash
# Verify the installed Erlang/OTP and erts versions
erl -eval 'io:format("OTP ~s / erts ~s~n", [erlang:system_info(otp_release), erlang:system_info(version)]), halt().' -noshell

# Expected patched output examples:
#   OTP 29 / erts 17.0.4
#   OTP 28 / erts 16.4.0.4
#   OTP 27 / erts 15.2.7.11

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.