CVE-2026-55737
Executive Summary
CVE-2026-55737 is a heap pointer corruption vulnerability in the Erlang OTP runtime system (erts), specifically within the external term format (ETF) decoder. A signed/unsigned integer mismatch when processing the LARGE_TUPLE_EXT term type allows a maliciously crafted binary passed to binary_to_term/1 to move the BEAM heap allocation pointer backward, leading to an out-of-bounds write and virtual machine crash. The attack is delivered via a small, compressed ETF envelope, enabling a denial-of-service (DoS) condition against any Erlang node that decodes untrusted external terms. The issue affects all OTP releases from 25.0 up to (but not including) the fixed versions 27.3.4.15, 28.5.0.4, and 29.0.4. No public exploit code exists, and the vulnerability is not listed in CISA KEV; the CVSS score is N/A and the EPSS score is 0.00126 (2.7% percentile of exploited CVEs).
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Technical Analysis
The vulnerability resides in erts/emulator/beam/external.c, in the ETF decoder responsible for parsing LARGE_TUPLE_EXT term headers. ETF is a binary serialization format used by Erlang for distribution, inter-process communication, and persistence (e.g., term_to_binary/1 and binary_to_term/1).
Root Cause — Signed/Unsigned Mismatch:
Validation pass (
decoded_size()): When the decoder traverses an incoming ETF binary to compute the required heap space, it reads the 32-bit arity field ofLARGE_TUPLE_EXTusingget_uint32(). This treats the wire value as an unsigned 32-bit integer. An arity value of0x80000000(binary value 2147483648) passes this validation as a legitimate, positive number.Decode pass (
dec_term()): During the actual term construction, the same 32-bit field is read usingget_int32()into a signedintvariable. The value0x80000000is interpreted as-2147483648.Heap pointer arithmetic: The decoder performs
hp += nwherenis the (now negative) arity value. The BEAM heap allocation pointer (hp) moves backward instead of forward. This corrupts the heap pointer before any tuple element is written.Missing bounds check: Neither pass enforces the runtime constant
MAX_ARITYVAL(which limits tuple arity to0x7FFFFF≈ 8.4 million). The validation pass only checks the total size, and the decode pass trusts the validated value implicitly.
Attack Surface & Delivery:
- The attacker does not need network access to the Erlang node itself if
binary_to_term/1is applied to data that crosses a trust boundary (e.g., a socket, HTTP request body, MQTT payload, or a file upload). - The payload is a standard ETF binary:
131(version tag) +104(LARGE_TUPLE_EXTtag) + 4 bytes of arity (0x00 0x00 0x00 0x80) + any additional term elements. When uncompressed, this is only ~6-8 bytes. - The ETF envelope supports compression (
131 80 83 ...with a zlib-compressed payload); the compressed size remains small, making the payload trivial to embed in any protocol that carries opaque binaries.
Impact on VM State:
- After the heap pointer is corrupted, the VM's memory manager detects an inconsistent heap state (impossible heap size or a pointer outside the allocated area), triggering an
erl_abort()and a process crash. - In a multi-node Erlang cluster, this can cascade as the node becomes unreachable, affecting connected services.
Exploitation Scenarios
Scenario 1: Remote DoS via Application-Layer Deserialization
Reconnaissance: The attacker identifies an Erlang application exposing a network endpoint that accepts
binary_to_term/1on user-supplied input. Common targets include RabbitMQ (management API), Riak, CouchDB, Apache CouchDB, or custom Erlang services usinggen_tcp,cowboy, orranch. A Shodan search forproduct:"Erlang"or"beam.smp"reveals exposed beam.smp processes.Weaponization: The attacker constructs the ETF payload:
- Envelope:
\x83\x68\x00\x00\x00\x80(version tag 131, LARGE_TUPLE_EXT tag 104, arity 0x80000000). - To bypass minimal packet inspection, the attacker can wrap this in the compressed ETF envelope (
\x83\x80\x83+ zlib stream). The compressed size is approximately 20-30 bytes including the zlib header and CRC.
- Envelope:
Delivery & Execution: The attacker sends this binary as the message body or as a field in a JSON/XML wrapper (if the app decodes a base64-encoded ETF). Example for an HTTP endpoint:
POST /api/ingest HTTP/1.1Content-Type: application/octet-stream- Body: base64 of the compressed ETF. Alternatively, for a raw TCP service: connect and send the raw ETF bytes directly without any protocol framing.
Post-Exploitation: The
binary_to_term/1call executes during input parsing. The VM detects the corrupted heap pointer and aborts, crashing the entire Erlang VM (not just the calling process). All connections are dropped; the service becomes unavailable. If the node is part of a cluster, thedistributedOTP application nodes will attempt to reconnect, but the crash persists until the operator restarts the service.
Scenario 2: Internal Attack via Message Queue
Reconnaissance: The attacker has access to a message broker (e.g., RabbitMQ) used by an Erlang microservice. The attacker identifies that messages with an
erlang:binary_to_term/1step are re-published in an internal queue.Weaponization: Same ETF payload as above, embedded as the message body. RabbitMQ's Erlang client library handles the envelope transparently; the attacker controls the raw binary content.
Delivery & Execution: The attacker publishes a single message to the ingestion queue. The consuming Erlang service decodes it, triggering the heap corruption and VM crash.
Post-Exploitation: The service dies; the queue accumulates messages. The operator restarts the service, which resumes processing the queue, re-triggering the crash each time until the malicious message is purged. This creates a persistent DoS loop.
Impact Assessment
Business Impact: High availability risk. A single 6-byte payload can crash an entire Erlang VM, taking down all applications hosted on that node. In clustered deployments, a crash can cause session state loss, distributed cache invalidation, and message rebalancing overhead.
Affected Systems: All Erlang/OTP installations using erts 13.0 – 15.2.7.10, 16.4.0 – 16.4.0.3, or 17.0 – 17.0.3. This includes production systems running RabbitMQ, Ejabberd, Riak, CouchDB, WhatsApp's servers (historical), and numerous fintech/cryptocurrency exchanges that historically used Erlang for backend services.
Blast Radius:
- Direct: Erlang VM crash → full service outage.
- Indirect: dependent microservices waiting on the crashed node's responses also fail; monitoring alerts trigger; incident response overhead.
- Supply chain: any product embedding OTP (e.g., some IoT gateways, telecom equipment) inherits the vulnerability even if the vendor never exposes ETF decoding directly to users.
CVSS Context: No CVSS vector has been published (score N/A). Based on impact assessment, if scored, this would likely rate around 7.5–8.5 (High) under CVSS 3.1, given the low attack complexity, network attack vector (via application layer), and high availability impact, but the absence of confidentiality/integrity impact lowers the ceiling. EPSS score 0.00126 indicates no active exploitation observed.
Detection Guidance
Sigma Rule
title: Erlang binary_to_term Heap Corruption Attempt (CVE-2026-55737)
status: experimental
description: Detects Erlang application logs indicating a crash caused by large tuple arity decoding failure, indicative of CVE-2026-55737 exploitation.
author: Valtersit Threat Intel
logsource:
product: application
service: erlang
category: error
detection:
selection_abort:
- c_harness: "erts_abort"
- message: "*impossible tuple size*"
- message: "*heap pointer corruption*"
- message: "*external term format*"
selection_erlang_crash:
- message: "*LARGE_TUPLE_EXT*"
- message: "*binary_to_term*"
condition_abort: selection_abort
condition_general: selection_erlang_crash and selection_abort
timeframe: 5m
condition: condition_abort or condition_general
level: high
falsepositives:
- Legitimate but malformed ETF binaries from buggy Erlang applications
fields:
- src_ip
- hostname
- node_name
- message
tags:
- attack.t1499
- attack.impact
- cve.2026-55737
- cwe.195
YARA Rule
rule Erlang_ETF_LargeTuple_Heap_Corruption {
meta:
author = "Valtersit Threat Intel"
description = "Detects ETF binary containing LARGE_TUPLE_EXT with arity 0x80000000 (CVE-2026-55737 trigger payload)"
reference = "CVE-2026-55737"
date = "2026-01-01"
score = 60
strings:
$version_tag = { 83 } // 131 (0x83) - ETF version tag
$large_tuple = { 68 } // 104 (0x68) - LARGE_TUPLE_EXT tag
$arity_msb = { 00 00 00 80 } // arity = 0x80000000 (as uint32)
$arity_msb_compressed = { 78 9C } // zlib header for compressed envelope
condition:
($version_tag at 0 and $large_tuple at 1 and $arity_msb at 2) or
($version_tag at 0 and $large_tuple at 1 and $arity_msb at 3) or
($arity_msb and $arity_msb_compressed and filesize < 100)
}
Suricata IDS Rule
alert tcp any any -> any any (msg:"ET EXPLOIT Erlang OTP CVE-2026-55737 LARGE_TUPLE_EXT Heap Corruption Attempt"; flow:established,to_server; content:"|83 68 00 00 00 80|"; fast_pattern:only; sid:202655737; rev:1; classtype:attempted-dos; reference:cve,2026-55737; reference:url,https://nvd.nist.gov/vuln/detail/CVE-2026-55737; metadata:created_at 2026_01_01, updated_at 2026_01_01;)
Elastic Detection
// Elastic EQL to detect Erlang VM crash logs or unusual ETF decoding errors
sequence by host.name, process.executable with maxspan=1m
[ process where process.name == "beam.smp" and
event.category == "process" and event.type == "start" ]
[ process where process.name == "beam.smp" and
event.action == "abort" and
wildcard(process.command_line, "*erts_abort*") or
wildcard(process.command_line, "*impossible tuple size*") or
wildcard(process.command_line, "*heap corruption*") ]
Splunk SPL Query
index=erlang sourcetype=erlang:crash
| where match(_raw, "(?i)(erts_abort|impossible tuple size|heap pointer corruption)")
| rex field=_raw "node=(?<node_name>\S+);"
| rex field=_raw "message=(?<crash_message>.*)"
| table _time, host, node_name, crash_message
| stats count by host, node_name, crash_message
| sort - _time
Wazuh OSSEC Rule
<group name="erlang,">
<rule id="791904" level="12">
<decoded_as>erlang_crash_log</decoded_as>
<field name="message">\.*erts_abort\.*|\.*impossible tuple size\.*|\.*heap pointer corruption\.*</field>
<description>Erlang OTP CVE-2026-55737 heap corruption attempt detected on node $(node_name)</description>
<group>dos_attempt,</group>
<mitre>
<id>T1499</id>
</mitre>
<options>no_full_log</options>
</rule>
<rule id="791905" level="10">
<if_sid>57100</if_sid>
<same_field>srcip</same_field>
<description>Erlang VM crash linked to CVE-2026-55737 from src IP $(srcip)</description>
<group>repeated_offender,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch confidence: 2/4 (CLAIMED — single source claims patch, not independently confirmed). The OSV advisory lists fixed versions, but no vendor bulletin has been published yet; treat the fix as provisional until Erlang/OTP releases an official security advisory.
1. Immediate Mitigations (no patch deployed)
- Scope allowlist for
binary_to_term/1: Wherever possible, wrap calls tobinary_to_term/1in acatchand only invoke it on data from trusted internal sources. Never expose it directly to network input. - Input validation pre-filter: Before calling
binary_to_term/1, validate the ETF structure using a lightweight external checker (e.g., a small Rust or Go service) that rejects tuples with arity >8,388,607(0x7FFFFF). This prevents the malicious binary from reaching the vulnerable decoder. - Disable compressed ETF: If the application does not require compressed ETF envelopes, strip/decompress the envelope before processing; the uncompressed form is easier to inspect for anomalies.
- Rate-limit and resource caps: Apply per-client rate limiting on endpoints that accept deserialized data to slow down repeated crash attempts.
- Failover architecture: Ensure at least two Erlang nodes behind a load balancer so a single crash does not cause full downtime; configure
OTPDistribution auto-reconnection.
2. Patch / Upgrade Steps
- Identify exact version: Run
erl -eval 'erlang:system_info(otp_release)' -noshell -s init stop. - Upgrade to fixed build:
- OTP 25.x — upgrade to 27.3.4.15 (or later 27.x) — note: OTP 25 is EOL; a direct jump to 27.3.4.15+ is required.
- OTP 28.5.x — upgrade to 28.5.0.4.
- OTP 29.0.x — upgrade to 29.0.4.
- If currently on OTP < 25, upgrade to at least 27.3.4.15.
- After upgrade, run the OTP test suite (
make test) and verifybinary_to_term/1works with existing stored ETF binaries. - Verify patch: Trigger the vulnerability in a test environment using the crafted payload; the VM should reject the tuple with a proper error (
badargorsystem_limit) instead of aborting.
3. Long-Term Hardening
- Enable
etssafe memory trimming: Configure+hmsand+hmbsVM flags to reduce heap fragmentation, limiting the damage from a heap-pointer jump. - Use
erlang:binary_to_term/2with[safe]option: This enforcesMAX_ARITYVALand rejects invalid tuples; replace all uses ofbinary_to_term/1with the safe variant where possible. - Network isolation: Run Erlang nodes in internal network segments; do not expose
beam.smpto the public internet. - Threat hunting: Deploy the Sigma/YARA/Suricata rules above in production to detect and log any attempt to deliver malformed ETF binaries; add SIP (source IP-based) alerts for repeated attempts.
- Update policy: Subscribe to the
erlang-otpsecurity mailing list and the OSV API for OTP; prioritize security patches within 72 hours for production clusters.
References
- NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2026-55737
- OSV Advisory: https://osv.dev/vulnerability/CVE-2026-55737 (single source claiming the patch; no vendor confirmation yet)
- Erlang/OTP Security Page: https://erlang.org/security (check for an official advisory once released)
- CVE Details (cvedetails.com): https://www.cvedetails.com/cve/CVE-2026-55737/
- CISA Known Exploited Vulnerabilities Catalog: https://www.cisa.gov/known-exploited-vulnerabilities-catalog — Not listed (KEV = NO), indicating no observed in-the-wild exploitation as of this report date.
Threat Actor Campaigns & EITW Evidence: No known adversary campaigns have been publicly attributed to this specific CVE. The EPSS score of 0.00126 suggests very low general interest, likely because the vulnerability requires a niche stack (Erlang) and has no direct data-exfiltration impact. However, state-sponsored APT groups historically target messaging platforms (e.g., past RabbitMQ exploits) — monitor logs for any crashes coinciding with anomalous inbound connections from non-standard IPs.
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.