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

CVE-2026-65634: Erlang/OTP ASN.1 OID DoS Vulnerability

CVE-2026-65634 is a denial of service flaw in Erlang/OTP ASN.1 OBJECT IDENTIFIER decoder that allows remote attackers to exhaust CPU resources during TLS handshakes. This post covers technical details, affected versions, and mitigation.

Published:

CVE-2026-65634 Overview

CVE-2026-65634 is an algorithmic complexity vulnerability in the Erlang/OTP asn1 library's OBJECT IDENTIFIER (OID) decoder. A remote unauthenticated attacker can send a crafted OID during the TLS handshake to trigger quadratic CPU work in the decoder. Because the vulnerable code path runs inside public_key:pkix_decode_cert/2 before any signature or trust chain verification, any Erlang service that parses peer TLS certificates is exposed. This includes default TLS clients that parse the server certificate and mutual-TLS servers that parse client certificates. A single DER-encoded OID with roughly 262 KB of continuation bytes can consume approximately 13 seconds of CPU on typical hardware. The weakness is tracked as CWE-407: Inefficient Algorithmic Complexity.

Critical Impact

Unauthenticated attackers can exhaust CPU on Erlang TLS clients and mTLS servers by sending a single crafted certificate during the handshake.

Affected Products

  • Erlang/OTP 17.0 through versions before OTP 27.3.4.18
  • Erlang/OTP 28.x before 28.5.0.7
  • Erlang/OTP 29.x before 29.1.1 (corresponding to asn1 3.0 through before 5.3.4.3, 5.4.3.1, and 5.5.2)

Discovery Timeline

  • 2026-09-22 - CVE-2026-65634 published to NVD
  • 2026-09-22 - Last updated in NVD database

Technical Details for CVE-2026-65634

Vulnerability Analysis

The flaw lives in the BER OID decoder asn1rtt_ber:dec_subidentifiers/3 in lib/asn1/src/asn1rtt_ber.erl and the equivalent PER helper asn1rtt_per_common:dec_subidentifiers/3 in lib/asn1/src/asn1rtt_per_common.erl. Both accumulate a base-128 subidentifier into an unbounded integer using the expression (Av bsl 7) + H per continuation byte. Each shift and addition on the growing accumulator is linear in the number of bits already accumulated, producing quadratic total work in the length of a single subidentifier. The JER helper asn1rtt_jer:json2oid/1 in lib/asn1/src/asn1rtt_jer.erl exhibits the same class of unbounded-integer parsing when decoding a dot-separated OID from JSON.

Root Cause

The decoders never bound the size of a single OID arc. Erlang's arbitrary-precision integers make each bsl 7 operation on the accumulator progressively more expensive. Attackers can weaponize this to force disproportionate CPU consumption from a small network payload.

Attack Vector

The vulnerable decoder is generated into every ASN.1 module containing an OBJECT IDENTIFIER, including OTP-PUB-KEY, which is invoked during X.509 certificate parsing via public_key:pkix_decode_cert/2. Because certificate parsing runs before signature or trust chain validation, an unauthenticated peer can deliver the malicious OID inside a certificate presented during the TLS handshake. Repeated connections amplify the CPU cost into a denial-of-service condition.

text
%% Patch excerpt: bound the number of continuation bytes
%% Source: https://github.com/erlang/otp/commit/0fe2c02fdc06fab1c63be9db1a7456993d20f838
decode_tag(Buffer) ->
    decode_tag(Buffer, 0, 0).

decode_tag(<<0:1, PartialTag:7, Buffer/binary>>, N, TagAck) when N < 32 ->
    TagNo = (TagAck bsl 7) bor PartialTag,
    {TagNo, Buffer};
decode_tag(<<_:1, PartialTag:7, Buffer/binary>>, N, TagAck) when N < 32 ->
    TagAck1 = (TagAck bsl 7) bor PartialTag,
    decode_tag(Buffer, N + 1, TagAck1).

Source: GitHub Commit 0fe2c02. The patch adds an N < 32 guard that rejects overlong tag components before the accumulator can grow.

Detection Methods for CVE-2026-65634

Indicators of Compromise

  • Erlang scheduler threads pinned at 100% CPU shortly after inbound TLS connections from untrusted peers.
  • TLS handshakes that stall or time out on the certificate parsing stage without reaching ssl:connection_information/1.
  • Inbound X.509 certificates containing OBJECT IDENTIFIER arcs with abnormally long chains of continuation bytes (high bit set).

Detection Strategies

  • Instrument public_key:pkix_decode_cert/2 call sites and log any invocation that exceeds a small millisecond budget.
  • Perform inline DER inspection at TLS terminators or reverse proxies to reject certificates whose OID subidentifier length exceeds a sane bound (for example, 32 bytes).
  • Correlate spikes in scheduler utilization with source IPs opening new TLS or mTLS sessions to identify probable attackers.

Monitoring Recommendations

  • Track per-node Erlang scheduler utilization and run-queue length; sustained saturation without traffic growth warrants investigation.
  • Alert on TLS handshake latency percentiles regressing on services that accept peer certificates, especially mTLS endpoints.
  • Retain packet captures or JA3/JA4 fingerprints for handshake failures to enable retrospective analysis of malicious clients.

How to Mitigate CVE-2026-65634

Immediate Actions Required

  • Upgrade Erlang/OTP to 27.3.4.18, 28.5.0.7, or 29.1.1 (or a later release), which correspond to asn15.3.4.3, 5.4.3.1, and 5.5.2 respectively.
  • Rebuild and redeploy any release that vendors its own asn1 beam files; simply updating the runtime is insufficient if generated modules are shipped inside the release.
  • Audit all Erlang services that terminate TLS or perform mTLS and prioritize internet-exposed nodes.

Patch Information

The fix is available in the upstream commit erlang/otp@0fe2c02 and documented in the GitHub Security Advisory GHSA-qghx-23m5-r55m. Additional detail is available in the Erlang Ecosystem Foundation CNA record and the OSV vulnerability record. The patch caps OID tag components at 32 continuation bytes and rejects overlong JSON-encoded OID components in json2oid/1.

Workarounds

  • Terminate TLS at a non-Erlang proxy that validates certificate structure and rejects malformed OIDs before the traffic reaches Erlang nodes.
  • Disable optional mTLS on services that do not strictly require it to reduce the attack surface for unauthenticated clients.
  • Apply per-source connection rate limiting and CPU cgroups to contain scheduler exhaustion until the runtime upgrade is deployed.
bash
# Verify the installed OTP version meets the fixed release
erl -eval 'io:format("~s~n", [erlang:system_info(otp_release)]), halt().' -noshell

# Confirm the asn1 application version loaded at runtime
erl -eval 'application:load(asn1), {ok, V} = application:get_key(asn1, vsn), io:format("asn1 vsn: ~s~n", [V]), halt().' -noshell

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

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.