CVE-2026-43966 Overview
CVE-2026-43966 is an HTTP Response Splitting vulnerability in ninenines/cowlib, the HTTP encoder/decoder library used by the Cowboy and Gun Erlang projects. The flaw lives in cow_http_struct_hd:escape_string/2, which escapes only \ and " while letting all other bytes — including carriage return (\r) and line feed (\n) — pass through verbatim. Applications that build structured HTTP headers from attacker-controlled input through cow_http_struct_hd:item/1 or wrappers such as cow_http_hd:wt_protocol/1 can have CRLF sequences injected into serialized header values. The issue affects cowlib from version 2.9.0.
Critical Impact
Attackers can inject arbitrary HTTP headers and split a single response into two, enabling cache poisoning, session fixation, and reflected cross-site scripting against downstream clients and proxies.
Affected Products
- ninenines/cowlib from version 2.9.0
- Cowboy HTTP server (consumes cowlib for header encoding)
- Gun HTTP client (consumes cowlib for header encoding)
Discovery Timeline
- 2026-06-08 - CVE-2026-43966 published to the National Vulnerability Database (NVD)
- 2026-06-09 - Last updated in NVD database
Technical Details for CVE-2026-43966
Vulnerability Analysis
The vulnerability is classified under [CWE-113]: Improper Neutralization of CRLF Sequences in HTTP Headers. The defect is an encoder/decoder asymmetry inside cowlib's RFC 8941 structured fields implementation. The parser accepts only printable ASCII bytes in the range 0x20–0x7E, excluding " and \. The encoder, however, emits any byte handed to it as long as " and \ are escaped. An attacker who controls a string passed to cow_http_struct_hd:item/1 can supply bytes outside the parser's accepted range, including 0x0D and 0x0A.
When the resulting header reaches the wire, the injected \r\n terminates the current header line. Any bytes after the CRLF are parsed by downstream HTTP agents as a fresh header — or even as a second HTTP response when followed by an empty line. This is the canonical primitive for HTTP Response Splitting.
Root Cause
The root cause is incomplete neutralization in cow_http_struct_hd:escape_string/2. The function should reject or escape all bytes the matching parser refuses to accept, but it only handles the two characters required by the structured-fields string grammar's literal escape rule. Non-VCHAR bytes such as CR, LF, NUL, and other control characters are serialized unchanged.
Attack Vector
Exploitation requires an application built on Cowboy or Gun that takes user input, places it into a structured-field header value, and sends the resulting response or request to a downstream party. The attacker submits a value containing \r\n followed by attacker-chosen header lines or response bodies. The vector is network-accessible and requires no authentication, but the application must propagate untrusted data into a structured header — the active attack requirement reflected in the CVSS attack requirements metric.
No public proof-of-concept code is available. The upstream fix is published in the Cowboy security commit and the Gun security commit. Refer to the Erlang Ecosystem Foundation advisory for the authoritative technical write-up.
Detection Methods for CVE-2026-43966
Indicators of Compromise
- HTTP response headers containing unexpected duplicate header names, particularly Content-Length, Content-Type, or Set-Cookie, following a structured-field header emitted by a Cowboy-based service.
- Outbound responses from Cowboy listeners whose raw byte streams contain 0x0D 0x0A inside a structured-field header value before the header's terminator.
- Access log entries where request parameters mapped to structured headers contain URL-encoded %0d%0a sequences or raw CR/LF bytes.
Detection Strategies
- Inspect the Erlang/OTP application dependency tree and flag any project resolving cowlib at version 2.9.0 or later that has not been updated to the patched release.
- Deploy a reverse proxy or WAF rule that drops requests containing \r or \n in fields that the application maps into structured headers such as priority, accept-ch, or custom wt_protocol values.
- Add fuzz tests around any application code path that calls cow_http_struct_hd:item/1 or cow_http_hd:wt_protocol/1 with untrusted input.
Monitoring Recommendations
- Log full outbound HTTP headers from Cowboy listeners during the remediation window and alert on any header value containing control bytes below 0x20.
- Monitor upstream caches and CDNs for cache key collisions or unexpected Vary and Set-Cookie headers attributable to Erlang-backed origins.
- Track dependency manifests (rebar.lock, mix.lock) in CI for downgrades or pins that reintroduce vulnerable cowlib versions.
How to Mitigate CVE-2026-43966
Immediate Actions Required
- Upgrade cowlib to the patched release referenced in the Erlang Ecosystem Foundation CNA advisory and rebuild all dependent Cowboy and Gun applications.
- Audit application code for calls to cow_http_struct_hd:item/1, cow_http_struct_hd:list/1, cow_http_struct_hd:dictionary/1, and cow_http_hd:wt_protocol/1 that take untrusted input.
- Reject or strictly validate user-supplied values destined for structured headers, allowing only 0x20–0x7E excluding " and \.
Patch Information
Upstream fixes are available in the Cowboy commit f77cb9b and the Gun commit 4f35609. The patch tightens escape_string/2 so that bytes outside the parser's accepted set are rejected rather than emitted. The vulnerability tracking entry is mirrored at the OSV record for EEF-CVE-2026-43966.
Workarounds
- Pre-validate every string passed into cow_http_struct_hd encoders, rejecting any byte outside 0x20–0x7E or matching " or \.
- Place a hardened reverse proxy in front of Cowboy listeners that normalizes outbound headers and strips CR/LF from header values.
- Avoid exposing the wt_protocol and other structured-field encoders to user-controlled input until the patched cowlib version is deployed.
# Update cowlib in a rebar3 project, then verify the resolved version
rebar3 upgrade cowlib
rebar3 tree | grep cowlib
# Update cowlib in a Mix (Elixir) project consuming Cowboy/Plug
mix deps.update cowlib
mix deps | grep cowlib
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

