CVE-2026-59251 Overview
CVE-2026-59251 is a denial of service vulnerability in Erlang/OTP's public_key application affecting RFC 5280 certificate path validation. A remote unauthenticated attacker can crash the BEAM virtual machine by presenting a crafted X.509 certificate chain during the TLS handshake. The certificate policy tree maintained by pubkey_policy_tree grows without bounds, exhausting memory and pinning schedulers. The flaw impacts any TLS client validating a peer chain and any mutual-TLS server accepting client certificates. The vulnerability class is identical to OpenSSL's X509_verify_cert policy tree DoS. It is categorized under [CWE-770] (Allocation of Resources Without Limits).
Critical Impact
Any TLS endpoint that validates peer certificate chains can be crashed by a single crafted handshake, taking down the entire Erlang VM and every service it hosts.
Affected Products
- Erlang/OTP 26.2 through versions before OTP 29.0.4
- Erlang/OTP 28.5.0.4 (fixed release on the 28.x branch)
- Erlang/OTP 27.3.4.15 (fixed release on the 27.x branch), corresponding to public_key from 1.15 before 1.21.4, 1.20.3.4, and 1.17.1.5
Discovery Timeline
- 2026-07-27 - CVE-2026-59251 published to NVD
- 2026-07-30 - Last updated in NVD database
Technical Details for CVE-2026-59251
Vulnerability Analysis
The defect lives in public_key:pkix_path_validation/3, the function that walks an X.509 chain and applies RFC 5280 policy processing. During policy processing, pubkey_policy_tree maintains a tree of certificate policies extracted from each certificate in the chain. The helper routines pubkey_policy_tree:add_leaves/2 and pubkey_policy_tree:add_leaf_siblings/2 extend the tree by one node per policy per certificate. No cap exists on the total number of nodes.
When a chain of K certificates each declares M distinct policies, the tree grows on the order of M^K nodes. A modest chain with many policies per certificate is enough to pin BEAM schedulers and exhaust node memory. Because the work is performed inside a native validation path, the schedulers do not yield, and the entire VM becomes unresponsive before it crashes.
Root Cause
The root cause is missing input validation on attacker-controlled certificate content combined with unbounded resource allocation during policy tree construction. The affected files are lib/public_key/src/pubkey_policy_tree.erl and its exported helpers. The upstream fix introduces a monotonic policy_tree_node_count counter into the path_validation_state record and refactors add_leaves and add_leaf_siblings to accept the counter, aborting validation with a new policy_tree_exceeded error when the cap is reached.
Attack Vector
Exploitation requires only the ability to present a certificate chain to the victim. This is the normal precondition for any TLS handshake. A malicious TLS server can crash any Erlang client that validates the server chain (the SSL/TLS default). A malicious client can crash any Erlang server configured for mutual TLS. No authentication, user interaction, or prior access is required.
-record(path_validation_state,
{
valid_policy_tree,
+ %% Monotonic count of nodes ever added to policy tree (never decremented by pruning).
+ policy_tree_node_count = 1 :: non_neg_integer(),
user_initial_policy_set,
explicit_policy,
inhibit_any_policy,
Source: Erlang/OTP commit f04c6bba — the patch caps policy tree growth by tracking node counts in the validation state.
-export([add_leaves/2,
- add_leaf_siblings/2,
+-export([add_leaves/3,
+ add_leaf_siblings/3,
any_leaves/1,
all_leaves/1,
collect_qualifiers/2,
Source: Erlang/OTP commit f8580fc1 — the exported helpers now accept the running node count and return policy_tree_exceeded when the bound is exceeded.
Detection Methods for CVE-2026-59251
Indicators of Compromise
- Sudden BEAM VM crashes or oom-killer events on Erlang nodes handling TLS traffic
- Sustained scheduler saturation on a single node coinciding with an inbound or outbound TLS handshake
- TLS peer certificates that declare unusually large sets of certificate policy OIDs across multiple chain elements
- Repeated failed handshakes from the same remote peer preceding an availability outage
Detection Strategies
- Inspect captured TLS handshakes for certificate chains with an abnormal count of certificatePolicies extension entries per certificate
- Alert on Erlang crash dumps that reference pubkey_policy_tree, add_leaves, or add_leaf_siblings on the stack
- Correlate BEAM memory spikes with ssl application activity to identify handshakes that consume disproportionate memory
Monitoring Recommendations
- Track BEAM process memory, scheduler utilization, and reduction counts on all TLS-facing Erlang services
- Log the version of public_key and OTP in use on each node and flag hosts running versions before the fixed releases
- Enable TLS handshake failure logging at the application layer and forward events to a central SIEM for correlation across nodes
How to Mitigate CVE-2026-59251
Immediate Actions Required
- Upgrade Erlang/OTP to 29.0.4, 28.5.0.4, or 27.3.4.15, whichever matches the currently deployed release branch
- If upgrade is blocked, restrict which peers are allowed to complete a TLS handshake using network ACLs or a validating proxy
- Audit all Erlang services that terminate or initiate TLS, including internal service-to-service traffic and outbound API clients
Patch Information
The Erlang Ecosystem Foundation released fixed builds in OTP 29.0.4, OTP 28.5.0.4, and OTP 27.3.4.15, corresponding to public_key versions 1.21.4, 1.20.3.4, and 1.17.1.5. Details are documented in the GitHub Security Advisory GHSA-622p-qfh6-c352, the CNA advisory at cna.erlef.org, and the OSV record EEF-CVE-2026-59251. Version ordering rules are described in the Erlang versions documentation.
Workarounds
- Terminate TLS at an unaffected reverse proxy (for example, a hardened NGINX or HAProxy instance) so that certificate path validation is not performed by the vulnerable Erlang node
- For mutual TLS deployments, constrain the accepted client certificate issuers to a private CA that does not emit certificates containing large policy sets
- Restrict outbound TLS destinations from Erlang services to an allowlist, reducing exposure to hostile server certificates
# Verify the installed OTP and public_key versions on each node
erl -noshell -eval 'io:format("OTP: ~s~npublic_key: ~s~n", [erlang:system_info(otp_release), begin {ok, V} = application:get_key(public_key, vsn), V end]), halt().'
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

