CRLF injection in cookie domain/path options in hackney
Description
Improper Neutralization of CRLF Sequences ('CRLF Injection') vulnerability in benoitc hackney allows HTTP Response Splitting. The hackney_cookie:setcookie/3 function in src/hackney_cookie.erl validates the Name and Value arguments against CRLF and control characters, but concatenates the domain and path options verbatim into the output iolist with no equivalent check. An attacker who controls either option — for example by supplying a Host header value forwarded as the cookie domain, or a request path forwarded as the cookie path — can inject a literal CRLF sequence and arbitrary additional Set-Cookie headers into the HTTP response.
This issue affects hackney: from 0.9.0 before 4.0.1.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CRLF injection in hackney_cookie:setcookie/3 allows HTTP response splitting via unvalidated domain/path options, affecting hackney 0.9.0 to 4.0.0.
Vulnerability
The vulnerability resides in the hackney_cookie:setcookie/3 function in src/hackney_cookie.erl. While the Name and Value arguments are validated against CRLF and control characters, the domain and path options are concatenated verbatim into the output iolist without equivalent checks. This affects hackney versions from 0.9.0 up to (but not including) 4.0.1 [1][2][3][4].
Exploitation
An attacker who controls either the domain or path option—for example, by supplying a Host header value forwarded as the cookie domain, or a request path forwarded as the cookie path—can inject a literal CRLF sequence and arbitrary additional Set-Cookie headers into the HTTP response. No authentication is required if the attacker can influence these options [2][4].
Impact
Successful exploitation enables HTTP response splitting, allowing an attacker to inject arbitrary cookies, perform session fixation, or strip Secure/HttpOnly flags from existing cookies. The CVSS v4.0 score is 2.1 (Low), reflecting the need for attacker-controlled input to reach the vulnerable options [2][4].
Mitigation
The issue is fixed in hackney version 4.0.1. The commit [3] adds validation for CR/LF, semicolon, and control characters in both domain and path options. Users should upgrade to 4.0.1 or later. No workaround is documented [1][3].
AI Insight generated on May 25, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
2Patches
18e02b99c28aefix(security): validate cookie domain/path options (GHSA-mp55)
2 files changed · +32 −2
src/hackney_cookie.erl+15 −2 modified@@ -46,11 +46,24 @@ setcookie(Name, Value, Opts) -> end, DomainBin = case lists:keyfind(domain, 1, Opts) of false -> <<>>; - {_, Domain} -> [<<"; Domain=">>, Domain] + {_, Domain} -> + %% GHSA-mp55: Name/Value are guarded above; Domain and + %% Path must reject the same line-terminating bytes (and + %% ';', which would start a new attribute) so a + %% request-derived domain/path cannot inject a second + %% Set-Cookie header. + nomatch = binary:match(iolist_to_binary(Domain), + [<<$;>>, <<$\s>>, <<$\t>>, <<$\r>>, + <<$\n>>, <<$\013>>, <<$\014>>, <<0>>]), + [<<"; Domain=">>, Domain] end, PathBin = case lists:keyfind(path, 1, Opts) of false -> <<>>; - {_, Path} -> [<<"; Path=">>, Path] + {_, Path} -> + nomatch = binary:match(iolist_to_binary(Path), + [<<$;>>, <<$\r>>, <<$\n>>, + <<$\013>>, <<$\014>>, <<0>>]), + [<<"; Path=">>, Path] end, SecureBin = case lists:keyfind(secure, 1, Opts) of false -> <<>>;
test/hackney_cookie_tests.erl+17 −0 modified@@ -99,3 +99,20 @@ setcookie_failures_test_() -> [{iolist_to_binary(io_lib:format("{~p, ~p} failure", [N, V])), fun() -> true = F(N, V) end} || {N, V} <- Tests]. + +%% GHSA-mp55: domain/path options must reject CR/LF/VT/FF/';' so a +%% request-derived value cannot split the Set-Cookie header. +setcookie_domain_path_injection_test_() -> + F = fun(Opts) -> + try hackney_cookie:setcookie(<<"sid">>, <<"abc">>, Opts) of + _ -> false + catch _:_ -> true + end + end, + Tests = [ + {"path CRLF", [{path, <<"/x\r\nSet-Cookie: admin=1; Path=/">>}]}, + {"path semicolon", [{path, <<"/x; Domain=evil">>}]}, + {"domain CRLF", [{domain, <<"x.example\r\nSet-Cookie: a=1">>}]}, + {"domain space", [{domain, <<"x.example evil">>}]} + ], + [{Name, fun() -> true = F(Opts) end} || {Name, Opts} <- Tests].
Vulnerability mechanics
Root cause
"Missing CRLF and control-character validation on the `domain` and `path` options in `hackney_cookie:setcookie/3` allows HTTP response splitting."
Attack vector
An attacker who controls the `domain` or `path` option passed to `hackney_cookie:setcookie/3` can inject a literal CRLF sequence (`\r\n`) followed by arbitrary `Set-Cookie` header content [ref_id=2]. This is realistic when the cookie domain is derived from the `Host` header, the cookie path is derived from the request URI, or a `Location` path is copied into a cookie [ref_id=2]. The injected CRLF splits the HTTP response header, allowing the attacker to add a second `Set-Cookie` header (e.g., `admin=1`) that can overwrite session cookies or strip security flags [ref_id=2].
Affected code
The vulnerability resides in `src/hackney_cookie.erl`, specifically in the `hackney_cookie:setcookie/3` function. The `DomainBin` and `PathBin` clauses (lines 47 and 51 of the original file) concatenate the `domain` and `path` options directly into the output iolist without any CRLF or control-character validation [ref_id=2]. The `Name` and `Value` arguments are guarded by a `binary:match` rejection set, but the domain and path options bypass that check entirely [ref_id=2].
What the fix does
The patch [patch_id=2473712] adds a `binary:match` guard to both the `Domain` and `Path` clauses in `hackney_cookie:setcookie/3`, rejecting the same set of dangerous bytes already blocked for `Name` and `Value`: `;`, `\r`, `\n`, `\013` (vertical tab), `\014` (form feed), and null byte `0` [ref_id=1]. The domain clause additionally rejects space and tab characters [ref_id=1]. If any of these bytes appear in the domain or path option, the match raises a `nomatch` exception, preventing the CRLF injection from reaching the output iolist [patch_id=2473712].
Preconditions
- inputThe attacker must control the value passed as the `domain` or `path` option to `hackney_cookie:setcookie/3`
- configThe caller must derive the domain or path option from attacker-influenced request data (e.g., Host header, request URI)
Reproduction
Call `hackney_cookie:setcookie(<<"sid">>, <<"abc">>, [{path, <<"/x\r\nSet-Cookie: admin=1; Path=/">>}])`. The returned binary contains a literal `\r\n` followed by a second `Set-Cookie:` line. When written into an HTTP response header, the client parses two headers, including `admin=1` [ref_id=2].
Generated on May 25, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4- github.com/benoitc/hackney/commit/8e02b99c28aea1b3fa2ddc0e66f51fe5bb0ac540mitrepatch
- github.com/benoitc/hackney/security/advisories/GHSA-mp55-p8c9-rfw2mitrevendor-advisoryrelated
- cna.erlef.org/cves/CVE-2026-47069.htmlmitrerelated
- osv.dev/vulnerability/EEF-CVE-2026-47069mitrerelated
News mentions
0No linked articles in our index yet.