CVE-2026-47066 Overview
CVE-2026-47066 is an infinite loop vulnerability in the benoitc/hackney Erlang HTTP client library. The flaw resides in the Alt-Svc response header parser at src/hackney_altsvc.erl. When parse_token/2 encounters a non-token, non-whitespace, non-comma byte such as !, @, =, or ;, it returns the input unchanged. The skip_comma/1 function exhibits the same behavior, causing parse_entries/2 to recurse with identical data. This creates a tight tail-recursive loop that pins a scheduler at 100% CPU. A single malformed Alt-Svc: ! response header from any HTTP origin triggers the hang [CWE-835].
Critical Impact
A single-byte malicious response header from any HTTP server the client connects to causes the calling process to hang indefinitely, exhausting an Erlang scheduler.
Affected Products
- benoitc hackney 2.0.0-beta.1 through versions prior to 4.0.1
- Erlang/Elixir applications using hackney as an HTTP client
- Downstream libraries depending on hackney (such as HTTPoison)
Discovery Timeline
- 2026-05-25 - CVE-2026-47066 published to NVD
- 2026-05-27 - Last updated in NVD database
Technical Details for CVE-2026-47066
Vulnerability Analysis
The vulnerability stems from a loop with an unreachable exit condition in the Alt-Svc header parser. The parse_and_cache/3 entry point is invoked synchronously in the connection process for every HTTP response received. When the parser encounters an unrecognized byte, none of the helper functions advance the input buffer position. The recursive call to parse_entries/2 then operates on identical data, producing infinite recursion.
Because Erlang uses tail-call optimization, the loop does not exhaust the stack. Instead, it consumes one scheduler thread at 100% CPU indefinitely. The calling process never returns control to the application, effectively wedging the HTTP client.
Root Cause
The parse_token/2 function fails to guarantee forward progress when it receives bytes outside the expected token, whitespace, or comma classes. The companion skip_comma/1 function only advances when the leading byte is a comma. When both return the buffer unchanged, the parser enters a non-terminating state. The fix introduces a seek_next_entry/1 helper that scans forward to the next comma, ensuring at most one malformed entry is dropped while preserving forward progress.
Attack Vector
Any remote HTTP origin the hackney client connects to can deliver the malicious response header. The attack requires no authentication and no user interaction. An attacker controlling an upstream server, performing a man-in-the-middle attack on cleartext HTTP, or injecting headers via an open redirect chain can trigger the hang. Repeated requests can exhaust all schedulers, producing a full denial of service on the BEAM virtual machine.
parse_entries(<<>>, Acc) ->
lists:reverse(Acc);
parse_entries(Data, Acc) ->
- {Entry, Rest} = parse_entry(skip_ws(Data)),
+ Stripped = skip_ws(Data),
+ {Entry, Rest} = parse_entry(Stripped),
+ %% GHSA-6cp8: ensure forward progress. A leading non-token byte
+ %% (`!`, `@`, `=`, `;`, `.`, ...) makes parse_entry return
+ %% {undefined, Rest=Stripped}, which would otherwise loop forever.
+ %% Skip to the next ',' so at most one malformed entry is dropped.
+ Rest1 = case Entry of
+ undefined when Rest =:= Stripped -> seek_next_entry(Stripped);
+ _ -> Rest
+ end,
case Entry of
- undefined -> parse_entries(skip_comma(Rest), Acc);
- _ -> parse_entries(skip_comma(Rest), [Entry | Acc])
+ undefined -> parse_entries(skip_comma(Rest1), Acc);
+ _ -> parse_entries(skip_comma(Rest1), [Entry | Acc])
end.
+seek_next_entry(<<>>) -> <<>>;
+seek_next_entry(<<$,, _/binary>> = Data) -> Data;
+seek_next_entry(<<_, Rest/binary>>) -> seek_next_entry(Rest).
Source: GitHub Commit e548aba. This patch ensures the parser advances past malformed entries to the next comma delimiter.
Detection Methods for CVE-2026-47066
Indicators of Compromise
- Erlang scheduler threads pinned at 100% CPU with no corresponding workload
- Hung HTTP request processes that never return from hackney:request/5 calls
- Outbound HTTP responses containing malformed Alt-Svc headers with leading non-token bytes such as !, @, =, or ;
- Increasing process queue lengths in BEAM telemetry for connection processes
Detection Strategies
- Inventory application dependencies for hackney versions between 2.0.0-beta.1 and 4.0.1 using mix deps or rebar3 tree
- Inspect HTTP response captures for Alt-Svc headers that begin with non-token characters
- Monitor BEAM scheduler utilization and identify long-running processes stuck in hackney_altsvc:parse_entries/2
Monitoring Recommendations
- Enable Erlang process tracing on connection processes to detect non-returning calls into the Alt-Svc parser
- Configure alerting on sustained 100% CPU on individual schedulers using observer or recon tooling
- Log and review outbound HTTP response headers at proxy boundaries for anomalous Alt-Svc values
How to Mitigate CVE-2026-47066
Immediate Actions Required
- Upgrade hackney to version 4.0.1 or later across all affected applications
- Audit transitive dependencies including HTTPoison and other libraries that bundle hackney
- Restrict outbound HTTP connections to trusted origins where feasible until patches are deployed
- Restart any long-running BEAM nodes after upgrade to clear potentially wedged processes
Patch Information
The upstream fix is available in commit e548aba1f97ffa3f4750da7b772998fb78c01894 and released in hackney 4.0.1. Details are published in GitHub Security Advisory GHSA-6cp8-v795-jr2j and the Erlang Ecosystem Foundation CNA advisory. The OSV record is available at OSV EEF-CVE-2026-47066.
Workarounds
- Route outbound HTTP traffic through a forward proxy that strips or sanitizes the Alt-Svc response header
- Set process timeouts on hackney calls using Task.async plus Task.yield patterns in Elixir or supervisor-enforced kill timers in Erlang to bound hung requests
- Disable connections to untrusted upstream services until the upgrade is complete
# Update hackney in a Rebar3 project
rebar3 upgrade hackney
# Update hackney in a Mix (Elixir) project
mix deps.update hackney
mix deps.get
# Verify installed version is 4.0.1 or later
mix deps | grep hackney
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.


