CVE-2026-69664
Executive Summary
CVE-2026-69664 is an unauthenticated denial-of-service vulnerability in the Erlang/OTP inets HTTP server (httpd). The flaw permits a remote attacker to exhaust all available worker processes by sending HTTP requests with a malformed chunked body where the chunk-size line is not a hexadecimal number, causing the serving worker to be permanently leaked without any timeout reclaiming it. The default configuration of inets httpd is vulnerable, meaning any internet-facing Erlang application using the built-in web server without additional hardening is at risk of complete service unavailability. No authentication is required and the impact is total resource exhaustion of the HTTP worker pool, effectively taking the service offline.
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 the interaction between the HTTP request parser and the Erlang process architecture used by the inets httpd module. The core flaw is a Missing Release of Resource after Effective Lifetime (CWE-772), wherein a worker process that completes its legitimate role (handling the headers of a request) is never released back to the pool when the body parsing path hits a specific error condition.
The trigger condition is a chunked-encoding HTTP request where the chunk-size line is not a valid hexadecimal number. The vulnerability manifests only when the chunk-size line is transmitted in a separate TCP write from the headers. This distinction is critical to the bypass:
Normal (patched-behavior) path: When the body accompanies the headers, the code calls
httpd_request_handler:handle_body/3, which invokeshttp_chunk:decode/3inside atry ... catch throw:Errorconstruct. In this case, the{error, {chunk_size, _}}tuple thrown byhttp_chunk:decode_size/4is handled correctly and converted into a 400 Bad Request response to the client.Vulnerable path: When the chunk-size line arrives in a subsequent write (separate TCP segment), the decoder is resumed through a different code path: a bare
catchexpression insidehttpd_request_handler:handle_info/2. In the Erlang virtual machine, a barecatchconverts athrowinto a return value rather than propagating it as an exception. As a result, the error tuple{error, {chunk_size, BadValue}}is treated as the next decoder continuation state, not as a failure condition.
The consequences of this conversion are:
- The socket is re-armed for reading (the handler returns a continuation that expects more data).
- The worker process enters a state where it waits indefinitely for data that will never arrive (since the client is not required to send anything further).
- The request timeout has already been cancelled at the point the headers were accepted — the timeout is armed only for the header-receiving phase.
- The periodic byte-rate check (which might otherwise reclaim the worker) is only armed when
minimum_bytes_per_secondis configured in the httpd configuration; this option is disabled by default.
Therefore, each malicious request permanently consumes one worker process from the pool. Since there is no timeout, no rate-limit check, and no error-path recovery, the worker is leaked forever. A remote attacker can repeat this request sequentially across many connections, eventually exhausting the entire worker pool. Once all workers are occupied, legitimate clients receive connection refusals or indefinite timeouts, resulting in complete denial of service.
The attack surface is the default inets httpd configuration. Any Erlang/OTP application that exposes the built-in HTTP server on an untrusted network is vulnerable. This includes applications that use inets for REST APIs, internal tooling, embedded devices, or management dashboards.
Affected Versions
- OTP 18.1.4 through 27.3.4.x (before 27.3.4.17)
- OTP 28.0 through 28.5.x (before 28.5.0.6)
- OTP 29.0 through 29.0.x (before 29.0.(early) — truncation in description suggests OTP 29.0.0)
Exploitation Scenarios
Attack Chain (inferred from vulnerability description):
Step 1 — Reconnaissance / Target Identification: An attacker performs network scanning to identify services running Erlang/OTP inets httpd. This can be achieved by banner grabbing (the server typically responds with Server: inets header or similar), or by fingerprinting response patterns unique to Erlang's HTTP stack. Services exposing management interfaces, device dashboards, or APIs built on Erlang (e.g., RabbitMQ management, Riak, CouchDB, or custom OTP applications) are prime targets.
Step 2 — Triggering the Flaw: The attacker opens a TCP connection to the HTTP port and sends an initial request with headers declaring Transfer-Encoding: chunked. The header block is sent and acknowledged. The attacker then sends a separate TCP write containing a chunk-size line that is not a hexadecimal number (e.g., ZZZ\r\n or XYZ9\r\n). Because this arrives as a distinct write after the headers, the decoder is resumed through the vulnerable handle_info/2 path rather than the protected handle_body/3 path.
Step 3 — Payload Execution: No traditional payload is required — this is a logic-flaw exhaustion attack. The malformed chunk-size line causes the decoder to enter the error tuple {error, {chunk_size, BadValue}} which is then treated as a valid continuation state. The worker process re-arms the socket and waits indefinitely. The server never sends a 400 response and never closes the connection. The attacker can leave the connection open or abandon it — the worker remains pinned.
Step 4 — Post-Exploitation Impact: The attacker repeats this procedure across multiple connections, one per available worker process. With a default concurrency configuration (typically a bounded number of workers), all workers are eventually exhausted. Legitimate clients attempting to connect receive connection timeouts or immediate connection refusal. The service is effectively down until the Erlang VM is restarted. Repeated exploitation is not required — once workers are leaked, they are never reclaimed via timeout, byte-rate checks, or connection-close handling, so the DoS state is permanent until process restart.
Attack complexity is LOW: The attacker needs only raw TCP socket access and the ability to split an HTTP request across two writes. There is no authentication, no special protocol knowledge beyond chunked encoding, and the vulnerability is in the default configuration.
Impact Assessment
Business Impact: Complete denial of service for any service relying on inets httpd. For Erlang-based products exposing REST APIs, management consoles, or device interfaces, this equates to full operational downtime. In production environments, this can halt order processing, monitoring, device management, or internal communication depending on the application's role.
Technical Impact: Exhaustion of the worker pool (finite resource) — all worker processes are leaked and never reclaimed. The Erlang VM itself remains healthy, meaning other non-HTTP components of the system (message queues, background jobs, distribution layer) continue running, but the HTTP frontend is completely unresponsive.
Affected Systems: All versions of Erlang/OTP using inets httpd from OTP 18.1.4 through OTP 27.3.x, OTP 28.0 to 28.5.x, and OTP 29.0 unless patched. The vulnerability affects default configurations, so no special settings are required for exposure.
CVSS Assessment: The NVD has not assigned a CVSS score. Based on the described characteristics: Attack Vector: Network, Attack Complexity: Low, Privileges Required: None, User Interaction: None, Scope: Unchanged, Confidentiality Impact: None, Integrity Impact: None, Availability Impact: High. This yields an approximate CVSS 3.1 score of 7.5 (HIGH). Note: The official CVSS vector is N/A per CVE data; use the NVD page for authoritative scoring when available.
Blast Radius: Any deployment exposing inets httpd to an untrusted network. Internal-only deployments are still at risk from lateral movement or compromised internal hosts. The vulnerability requires no credentials and no user interaction, making it ideal for automated botnet-style scanning.
Exploitation in the Wild: No public evidence of exploitation, no PoC, and no exploit code is available as of the time of this report.
Detection Guidance
Detection of this vulnerability is challenging because the attack traffic (split HTTP writes with malformed chunk sizes) may not generate error responses. The key indicators are: connections that send headers but never complete a valid request body and never receive a response, combined with worker pool exhaustion.
Sigma Rule
title: Erlang inets httpd Chunk-Size DoS - Excessive Stalled Connections
id: 57b77c2e-9f8d-4e0b-9f3a-1d8c71f8b3e5
status: experimental
description: Detects abnormal HTTP connections to Erlang inets httpd that send headers with chunked encoding but fail to send valid hexadecimal chunk-size lines, indicating attempted worker exhaustion (CVE-2026-69664)
logsource:
category: webserver
product: generic
detection:
selection_http:
cs-method: POST
cs-uri-query|contains:
- ""
selection_chunked:
cs-header: "*Transfer-Encoding: chunked*"
cs-header: "*Trailer*"
selection_abnormal:
cs-bytes:
- "0"
sc-status:
- "0"
condition: selection_http and selection_chunked and selection_abnormal
timeframe: 5m
level: high
falsepositives:
- Legitimate clients that start uploads and drop connections mid-transfer
- Slowloris-style attacks (same pattern may be reused by other DoS tools)
fields:
- srcip
- cs-method
- cs-uri-query
- sc-status
tags:
- attack.t1499
YARA Rule
rule Erlang_inets_chunked_dos_multiwrite {
meta:
author = "Valterits Threat Intelligence"
description = "Detect exploit attempts for CVE-2026-69664 - Erlang inets httpd chunk-size DoS"
reference = "CVE-2026-69664"
date = "2026-09-01"
severity = "high"
strings:
// Header marker for chunked transfer encoding
$transfer_encoding = "Transfer-Encoding: chunked" nocase
// Malformed hex characters that would trigger the vulnerable path
$bad_hex_chunk = /(\r\n)?[G-Zg-z][0-9A-Za-z]{0,3}\r\n/ nocase
// Inets server banner for fingerprinting
$inets_banner = "inets" nocase
condition:
$transfer_encoding and $bad_hex_chunk and $inets_banner
}
Note: This rule detects protocol-level anomalies in captured PCAP data; network captures must be reconstructed at TCP level to see which segments carry the chunk-size line.
Suricata IDS Rule
alert tcp any any -> any any (msg:"ET DOS Erlang inets httpd Malformed Chunk-Size - CVE-2026-69664";
flow:established;
content:"Transfer-Encoding: chunked";
nocase;
pcre:"/^[^\r\n]*\r\n\r\n[^0-9a-fA-F\r\n][0-9a-zA-Z]{0,3}\r\n/mi";
sid:2026069644;
rev:1;
classtype:attempted-dos;
metadata:created_at 2026_09_01, updated_at 2026_09_01, cve CVE-2026-69664)
Explanation: This rule looks for TCP streams containing Transfer-Encoding: chunked followed by a chunk-size line that begins with a non-hexadecimal character. The PCRE regex [^0-9a-fA-F\r\n] matches the first character of the chunk-size line not being hex. The rule targets the specific client-server protocol exchange.
Elastic Detection
// EQL query to detect workers exhaustion via abnormal connection behavior
sequence by process.entity_id
[ network where process.name == "beam.smp" and
event.action == "accept" and
network.direction == "inbound" and
destination.port == 80 ]
[ network where
network.protocol == "http" and
http.request.method == "POST" and
http.request.headers : "*Transfer-Encoding*chunked*" and
process.name == "beam.smp"
]
// No response is ever sent: connection duration exceeds threshold
[ network where
process.name == "beam.smp" and
event.kind == "end" and
network.bytes == 0 and
network.duration > 300000
] with maxspan=30m
Splunk SPL Query
index=proxy OR index=firewall sourcetype=stream:http
| search "Transfer-Encoding: chunked"
| rex field=_raw "(?i)Transfer-Encoding:\s*chunked"
| rex field=_raw "(?i)(?<payload>G-Z)"
| eval is_bad_chunk = if(match(_raw, "[G-Zg-z]"), "SUSPICIOUS", "normal")
| eval duration_seconds = (closed_time - open_time)
| where is_bad_chunk="SUSPICIOUS" AND (duration_seconds > 300 OR bytes_out=0)
| stats count as suspicious_conns by src_ip, dest_ip, dest_port
| where suspicious_conns > 5
| table _time, src_ip, dest_ip, dest_port, suspicious_conns
Wazuh OSSEC Rule
<group name="erlang_httpd,">
<!-- Detect attempts exposing the malformed chunk-size flag in HTTP body parsing -->
<rule id="100296" level="12">
<if_sid>31122</if_sid> <!-- Parent: HTTP request -->
<match>Transfer-Encoding: chunked</match>
<regex>^[^\r\n]*\r\n\r\n[G-Z][0-9A-Za-z]{0,3}\r\n</regex>
<description>Erlang inets httpd: malformed chunk-size line received, possible CVE-2026-69664 DoS attempt</description>
<group>dos_attack,http_request,</group>
<mitre>
<id>T1499</id>
</mitre>
</rule>
<!-- Detect high volume of POST / chunked requests coming from single source -->
<rule id="100297" level="10" frequency="20" timeframe="120">
<match>Transfer-Encoding: chunked</match>
<same_source_ip />
<description>Erlang inets httpd: anomalous number of chunked requests from single source, potential worker exhaustion</description>
<group>dos_attack,</group>
</rule>
</group>
Mitigation & Patch Guidance
Patch Confidence: 0/4 — UNPATCHED. There is currently no vendor patch, no workaround, and no firmware update available from any tracked source. The vulnerability remains exploitable in all affected versions.
1. Immediate Mitigations (until patch is available)
- Restrict network exposure: Place inets httpd behind a reverse proxy (e.g., nginx, HAProxy, Traefik) that normalizes incoming requests and rejects malformed chunked encoding before it reaches the Erlang process. This is the primary defense.
- Disable chunked transfer encoding: If the application does not require chunked request bodies, configure the reverse proxy or firewall to strip or reject any request carrying
Transfer-Encoding: chunkedheaders. - Implement connection-level rate limiting: Use firewall rules or a reverse proxy to limit the number of concurrent connections per source IP. Attackers using a single IP can be throttled or blocked. Note: This does not prevent distributed attacks.
- Configure
minimum_bytes_per_second: Set this option in the httpd configuration to a non-zero value (e.g.,{minimum_bytes_per_second, 100}). When enabled, the periodic byte-rate check is armed, and workers that stop sending data within the timeout period will be reclaimed. Verify the exact configuration syntax in your OTP documentation.
2. Patch/Upgrade Steps
- Monitor vendor advisories: Check Erlang/OTP releases page (https://www.erlang.org/patches/OTP-27.3.4.17, OTP-28.5.0.6) regularly for the patched versions. The affected version ranges indicate that fixes are imminent or in preparation.
- Upgrade once available: When the patched versions become available (OTP 27.3.4.17, OTP 28.5.0.6, OTP 29.0.x), upgrade all deployments immediately.
- Interim build: If the application is built from source, consider applying a local patch to
httpd_request_handler.erl— specifically, changing the barecatchinhandle_info/2to atry ... catch throw:Errorconstruct that raises the error tuple, matching thehandle_body/3behavior.
3. Long-Term Hardening
- Application-layer DoS protection: Deploy a WAF or HTTP-level mitigation tool that validates chunked encoding compliance and rejects malformed requests upstream.
- Process isolation: Run inets httpd in a dedicated Erlang VM instance. If exhausted, the DoS affects only the HTTP frontend, not other OTP applications or data services.
- Health checks and auto-restart: Implement supervision trees with restart strategies so that a worker-pool exhaustion triggers a supervisor restart of the httpd listener.
- Monitor for saturation: Continuously monitor HTTP response times, connection acceptance rates, and worker pool usage. Set alerts for connection refusal errors.
References
- NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2026-69664
- Erlang/OTP Releases & Patches: https://www.erlang.org/patches (official vendor page — monitor for OTP 27.3.4.17, OTP 28.5.0.6, OTP 29.0.x)
- Erlang/OTP Security Advisories: https://www.erlang.org/security-advisories (official vendor security page)
- CISA Known Exploited Vulnerabilities Catalog: https://www.cisa.gov/known-exploited-vulnerabilities-catalog (CVE-2026-69664 is NOT listed — status: NO)
- CWE-772 Reference: https://cwe.mitre.org/data/definitions/772.html (Missing Release of Resource after Effective Lifetime)
Exploit-in-the-Wild Evidence: None reported. No public PoC, no exploit code, no Nuclei template, and no CISA KEV listing as of this report. This may change rapidly once the vulnerability becomes widely known; monitor threat feeds.
Report Quality Notes: The NVD description provides excellent technical depth (function names httpd_request_handler:handle_body/3, http_chunk:decode/3, http_chunk:decode_size/4, httpd_request_handler:handle_info/2 are all quoted from the description and used above). The exact affected version for OTP 29.0 is truncated in the source data ("before O") — the report assumes the range continues but marks this as an unknown. CVSS remains N/A per NVD; the approximate score stated is an internal calculation and should be replaced when NVD publishes authoritative data.
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.