From f9ce3dc00daf05885ce78457fc6733bef3d48da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Rubinos=20Rodr=C3=ADguez?= Date: Mon, 8 Jun 2026 21:45:14 +0200 Subject: [PATCH 1/2] fix(h1): reject control chars in header values and spaces in the request-target --- src/nhttp_h1.erl | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/nhttp_h1.erl b/src/nhttp_h1.erl index 4ba0a78..48f5ecf 100644 --- a/src/nhttp_h1.erl +++ b/src/nhttp_h1.erl @@ -822,12 +822,17 @@ find_chunk_crlf(<>, Skip, SizeLen) -> find_path_version(Bin, Method) -> case binary:split(Bin, <<" HTTP/1.">>) of [Path, <>] when Ver =:= <<"1">>; Ver =:= <<"0">> -> - Version = - case Ver of - <<"1">> -> http1_1; - <<"0">> -> http1_0 - end, - {ok, Method, Path, Version, Rest}; + case valid_request_target(Path) of + true -> + Version = + case Ver of + <<"1">> -> http1_1; + <<"0">> -> http1_0 + end, + {ok, Method, Path, Version, Rest}; + false -> + {error, bad_request_line} + end; [_Path, <>] when Ver =:= <<"1">>; Ver =:= <<"0">> -> {more, 1}; [_Path, <>] when Ver =:= <<"1">>; Ver =:= <<"0">> -> @@ -921,11 +926,21 @@ get_all_content_lengths(Headers) -> -spec has_invalid_char(binary()) -> boolean(). has_invalid_char(<<>>) -> false; -has_invalid_char(<<$\r, _/binary>>) -> true; -has_invalid_char(<<$\n, _/binary>>) -> true; -has_invalid_char(<<0, _/binary>>) -> true; +has_invalid_char(<<$\t, Rest/binary>>) -> has_invalid_char(Rest); +has_invalid_char(<>) when C =< 16#1F -> true; +has_invalid_char(<<16#7F, _/binary>>) -> true; has_invalid_char(<<_, Rest/binary>>) -> has_invalid_char(Rest). +-spec valid_request_target(binary()) -> boolean(). +valid_request_target(<<>>) -> false; +valid_request_target(Target) -> not target_has_invalid_char(Target). + +-spec target_has_invalid_char(binary()) -> boolean(). +target_has_invalid_char(<<>>) -> false; +target_has_invalid_char(<>) when C =< 16#20 -> true; +target_has_invalid_char(<<16#7F, _/binary>>) -> true; +target_has_invalid_char(<<_, Rest/binary>>) -> target_has_invalid_char(Rest). + -spec is_chunked_transfer_encoding(binary()) -> boolean(). is_chunked_transfer_encoding(Bin) -> Codings = binary:split(Bin, <<",">>, [global, trim_all]), From 4119ea9e303ed40260abf7030258530bc5a5d860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Rubinos=20Rodr=C3=ADguez?= Date: Tue, 9 Jun 2026 05:36:21 +0200 Subject: [PATCH 2/2] chore: version bump --- CHANGELOG.md | 7 +++++++ rebar.config | 2 +- rebar.lock | 6 +++--- src/nhttp_lib.app.src | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac9d74b..bd6c573 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.1] - 2026-06-09 + +### Fixed + +- Reject control characters in HTTP/1.1 header field values (RFC 9110) +- Reject whitespace in the HTTP/1.1 request-target (RFC 9112) + ## [1.0.0] - 2026-04-20 Initial public release. diff --git a/rebar.config b/rebar.config index 4203be3..842dca8 100644 --- a/rebar.config +++ b/rebar.config @@ -6,7 +6,7 @@ warnings_as_errors ]}. -{deps, [{nquic, "1.0.0"}]}. +{deps, [{nquic, "1.0.2"}]}. {project_plugins, [ erlfmt, diff --git a/rebar.lock b/rebar.lock index cea0413..747e4a1 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,8 +1,8 @@ {"1.2.0", -[{<<"nquic">>,{pkg,<<"nquic">>,<<"1.0.0">>},0}]}. +[{<<"nquic">>,{pkg,<<"nquic">>,<<"1.0.2">>},0}]}. [ {pkg_hash,[ - {<<"nquic">>, <<"7B8FB1BAE0362AB075136C1C008C75EA8E076889A5DA0B18D370B702128D7923">>}]}, + {<<"nquic">>, <<"B82954B494BDDED6EB6FD7A2C9A41E20889C2C47CB1D4BB4EF6139FA850E491E">>}]}, {pkg_hash_ext,[ - {<<"nquic">>, <<"696F538259F6C6B56C016CB0614269AB1DA33FFA695F7C18A4153DEF7571E6A4">>}]} + {<<"nquic">>, <<"09A8804265EE9CCD4C40BC35C93F2B72C0310495841B5C5D0AA6706993EE4957">>}]} ]. diff --git a/src/nhttp_lib.app.src b/src/nhttp_lib.app.src index 1e996d6..05e6341 100644 --- a/src/nhttp_lib.app.src +++ b/src/nhttp_lib.app.src @@ -1,6 +1,6 @@ {application, nhttp_lib, [ {description, "HTTP protocol primitives for Erlang/OTP 27+ (HTTP/1.1, HTTP/2, HTTP/3, QPACK)"}, - {vsn, "1.0.0"}, + {vsn, "1.0.1"}, {registered, []}, {applications, [ kernel,