Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions SPECS/rabbitmq-server/CVE-2026-59248.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
From cc1e1e57ed9060646f6daafa5f898acb4cdd3e18 Mon Sep 17 00:00:00 2001
From: AllSpark <allspark@microsoft.com>
Date: Fri, 31 Jul 2026 07:19:42 +0000
Subject: [PATCH] Add a hard limit for HPACK integer decoding

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: AI Backport of https://github.com/ninenines/cowlib/commit/f582430498072a0c65ad338030321576dc13a343.patch
---
deps/cowlib/src/cow_hpack.erl | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/deps/cowlib/src/cow_hpack.erl b/deps/cowlib/src/cow_hpack.erl
index d7ae475..c2790eb 100644
--- a/deps/cowlib/src/cow_hpack.erl
+++ b/deps/cowlib/src/cow_hpack.erl
@@ -187,6 +187,10 @@ dec_lit_no_index(Rest, State, Acc, Name) ->
%% The HPACK format has 4 different integer prefixes length (from 4 to 7)
%% and each can be used to create an indefinite length integer if all bits
%% of the prefix are set to 1.
+%%
+%% We hard limit indefinite length integers to 38bits. The maximum
+%% possible value is large enough for normal use cases and does
+%% not produce an Erlang big int.

dec_int5(<< 2#11111:5, Rest/bits >>) ->
dec_big_int(Rest, 31, 0);
@@ -195,7 +199,7 @@ dec_int5(<< Int:5, Rest/bits >>) ->

dec_big_int(<< 0:1, Value:7, Rest/bits >>, Int, M) ->
{Int + (Value bsl M), Rest};
-dec_big_int(<< 1:1, Value:7, Rest/bits >>, Int, M) ->
+dec_big_int(<< 1:1, Value:7, Rest/bits >>, Int, M) when M < 32 ->
dec_big_int(Rest, Int + (Value bsl M), M + 7).

%% Decode a string.
@@ -254,6 +258,15 @@ decode_reject_eos_test() ->
{'EXIT', _} = (catch decode(<<16#0085f2b24a84ff874951fffffffa7f:120>>)),
ok.

+decode_reject_very_big_int_test() ->
+ VeryBigInt0 = binary:copy(<<16#ff>>, 32767),
+ VeryBigInt = <<VeryBigInt0/binary, 16#7f>>,
+ garbage_collect(),
+ Prev = process_flag(max_heap_size, #{size => 10_000, kill => true}),
+ {'EXIT', _} = (catch decode(VeryBigInt)),
+ process_flag(max_heap_size, Prev),
+ ok.
+
req_decode_test() ->
%% First request (raw then huffman).
{Headers1, State1} = decode(<< 16#828684410f7777772e6578616d706c652e636f6d:160 >>),
--
2.45.4

192 changes: 192 additions & 0 deletions SPECS/rabbitmq-server/CVE-2026-65624.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
From b0730f399a023dccd7b94c3af2196f13bc339763 Mon Sep 17 00:00:00 2001
From: AllSpark <allspark@microsoft.com>
Date: Fri, 31 Jul 2026 07:21:10 +0000
Subject: [PATCH] Fix HTTP/1.1 max_headers with duplicate headers

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: AI Backport of https://github.com/ninenines/cowboy/commit/3a34d8c1cfd94326466aa16a9017236691dc9c55.patch
---
deps/cowboy/src/cowboy_http.erl | 95 +++++++++++++++++++-------------
1 file changed, 56 insertions(+), 39 deletions(-)

diff --git a/deps/cowboy/src/cowboy_http.erl b/deps/cowboy/src/cowboy_http.erl
index a3bfd5b..3ca786d 100644
--- a/deps/cowboy/src/cowboy_http.erl
+++ b/deps/cowboy/src/cowboy_http.erl
@@ -71,6 +71,7 @@
qs = undefined :: binary(),
version = undefined :: cowboy:http_version(),
headers = undefined :: cowboy:http_headers() | undefined,
+ num_headers = 0 :: non_neg_integer(),
name = undefined :: binary() | undefined
}).

@@ -355,14 +356,16 @@ parse(_, State=#state{in_streamid=InStreamID, in_state=#ps_request_line{},
loop(State#state{buffer= <<>>});
parse(Buffer, State=#state{in_state=#ps_request_line{empty_lines=EmptyLines}}) ->
after_parse(parse_request(Buffer, State, EmptyLines));
-parse(Buffer, State=#state{in_state=PS=#ps_header{headers=Headers, name=undefined}}) ->
+parse(Buffer, State=#state{in_state=PS=#ps_header{
+ headers=Headers, num_headers=Num, name=undefined}}) ->
after_parse(parse_header(Buffer,
State#state{in_state=PS#ps_header{headers=undefined}},
- Headers));
-parse(Buffer, State=#state{in_state=PS=#ps_header{headers=Headers, name=Name}}) ->
+ Headers, Num));
+parse(Buffer, State=#state{in_state=PS=#ps_header{
+ headers=Headers, num_headers=Num, name=Name}}) ->
after_parse(parse_hd_before_value(Buffer,
State#state{in_state=PS#ps_header{headers=undefined, name=undefined}},
- Headers, Name));
+ Headers, Num, Name));
parse(Buffer, State=#state{in_state=#ps_body{}}) ->
after_parse(parse_body(Buffer, State)).

@@ -604,32 +607,33 @@ parse_version(_, State, _, _, _, _) ->

before_parse_headers(Rest, State, M, A, P, Q, V) ->
parse_header(Rest, State#state{in_state=#ps_header{
- method=M, authority=A, path=P, qs=Q, version=V}}, #{}).
+ method=M, authority=A, path=P, qs=Q, version=V}}, #{}, 0).

%% Headers.

%% We need two or more bytes in the buffer to continue.
-parse_header(Rest, State=#state{in_state=PS}, Headers) when byte_size(Rest) < 2 ->
- {more, State#state{buffer=Rest, in_state=PS#ps_header{headers=Headers}}};
-parse_header(<< $\r, $\n, Rest/bits >>, S, Headers) ->
+parse_header(Rest, State=#state{in_state=PS}, Headers, Num) when byte_size(Rest) < 2 ->
+ {more, State#state{buffer=Rest, in_state=PS#ps_header{
+ headers=Headers, num_headers=Num}}};
+parse_header(<< $\r, $\n, Rest/bits >>, S, Headers, _) ->
request(Rest, S, Headers);
-parse_header(Buffer, State=#state{opts=Opts, in_state=PS}, Headers) ->
+parse_header(Buffer, State=#state{opts=Opts, in_state=PS}, Headers, Num) ->
MaxHeaders = maps:get(max_headers, Opts, 100),
- NumHeaders = maps:size(Headers),
if
- NumHeaders >= MaxHeaders ->
- error_terminate(431, State#state{in_state=PS#ps_header{headers=Headers}},
+ Num >= MaxHeaders ->
+ error_terminate(431, State#state{in_state=PS#ps_header{
+ headers=Headers, num_headers=Num}},
{connection_error, limit_reached,
'The number of headers is larger than configuration allows. (RFC7230 3.2.5, RFC6585 5)'});
true ->
- parse_header_colon(Buffer, State, Headers)
+ parse_header_colon(Buffer, State, Headers, Num)
end.

-parse_header_colon(Buffer, State=#state{opts=Opts, in_state=PS}, Headers) ->
+parse_header_colon(Buffer, State=#state{opts=Opts, in_state=PS}, Headers, Num) ->
MaxLength = maps:get(max_header_name_length, Opts, 64),
case match_colon(Buffer, 0) of
nomatch when byte_size(Buffer) > MaxLength ->
- error_terminate(431, State#state{in_state=PS#ps_header{headers=Headers}},
+ error_terminate(431, State#state{in_state=PS#ps_header{headers=Headers, num_headers=Num}},
{connection_error, limit_reached,
'A header name is larger than configuration allows. (RFC7230 3.2.5, RFC6585 5)'});
nomatch ->
@@ -637,14 +641,14 @@ parse_header_colon(Buffer, State=#state{opts=Opts, in_state=PS}, Headers) ->
%% so check if we have an LF and abort with an error if we do.
case match_eol(Buffer, 0) of
nomatch ->
- {more, State#state{buffer=Buffer, in_state=PS#ps_header{headers=Headers}}};
+ {more, State#state{buffer=Buffer, in_state=PS#ps_header{headers=Headers, num_headers=Num}}};
_ ->
- error_terminate(400, State#state{in_state=PS#ps_header{headers=Headers}},
+ error_terminate(400, State#state{in_state=PS#ps_header{headers=Headers, num_headers=Num}},
{connection_error, protocol_error,
'A header line is missing a colon separator. (RFC7230 3.2.4)'})
end;
_ ->
- parse_hd_name(Buffer, State, Headers, <<>>)
+ parse_hd_name(Buffer, State, Headers, Num, <<>>)
end.

match_colon(<< $:, _/bits >>, N) ->
@@ -654,37 +658,46 @@ match_colon(<< _, Rest/bits >>, N) ->
match_colon(_, _) ->
nomatch.

-parse_hd_name(<< $:, Rest/bits >>, State, H, SoFar) ->
- parse_hd_before_value(Rest, State, H, SoFar);
-parse_hd_name(<< C, _/bits >>, State=#state{in_state=PS}, H, <<>>) when ?IS_WS(C) ->
- error_terminate(400, State#state{in_state=PS#ps_header{headers=H}},
+parse_hd_name(<< $:, Rest/bits >>, State, H, Num, SoFar) ->
+ parse_hd_before_value(Rest, State, H, Num, SoFar);
+parse_hd_name(<< C, _/bits >>, State=#state{in_state=PS}, H, Num, <<>>) when ?IS_WS(C) ->
+ error_terminate(400, State#state{in_state=PS#ps_header{headers=H, num_headers=Num}},
{connection_error, protocol_error,
'Whitespace is not allowed before the header name. (RFC7230 3.2)'});
-parse_hd_name(<< C, _/bits >>, State=#state{in_state=PS}, H, _) when ?IS_WS(C) ->
- error_terminate(400, State#state{in_state=PS#ps_header{headers=H}},
+parse_hd_name(<< C, _/bits >>, State=#state{in_state=PS}, H, Num, _) when ?IS_WS(C) ->
+ error_terminate(400, State#state{in_state=PS#ps_header{headers=H, num_headers=Num}},
{connection_error, protocol_error,
'Whitespace is not allowed between the header name and the colon. (RFC7230 3.2.4)'});
-parse_hd_name(<< C, Rest/bits >>, State, H, SoFar) ->
- ?LOWER(parse_hd_name, Rest, State, H, SoFar).
-
-parse_hd_before_value(<< $\s, Rest/bits >>, S, H, N) ->
- parse_hd_before_value(Rest, S, H, N);
-parse_hd_before_value(<< $\t, Rest/bits >>, S, H, N) ->
- parse_hd_before_value(Rest, S, H, N);
-parse_hd_before_value(Buffer, State=#state{opts=Opts, in_state=PS}, H, N) ->
+parse_hd_name(<< C, _/bits >>, State=#state{in_state=PS}, H, Num, _)
+ when C =:= $\r; C =:= $\n ->
+ error_terminate(400, State#state{in_state=PS#ps_header{headers=H, num_headers=Num}},
+ {connection_error, protocol_error,
+ 'A header line is missing a colon separator. (RFC7230 3.2.4)'});
+parse_hd_name(<< $\0, _/bits >>, State=#state{in_state=PS}, H, Num, _) ->
+ error_terminate(400, State#state{in_state=PS#ps_header{headers=H, num_headers=Num}},
+ {connection_error, protocol_error,
+ 'NUL byte is not allowed in header name. (RFC9110 5.5)'});
+parse_hd_name(<< C, Rest/bits >>, State, H, Num, SoFar) ->
+ ?LOWER(parse_hd_name, Rest, State, H, Num, SoFar).
+
+parse_hd_before_value(<< $\s, Rest/bits >>, S, H, Num, N) ->
+ parse_hd_before_value(Rest, S, H, Num, N);
+parse_hd_before_value(<< $\t, Rest/bits >>, S, H, Num, N) ->
+ parse_hd_before_value(Rest, S, H, Num, N);
+parse_hd_before_value(Buffer, State=#state{opts=Opts, in_state=PS}, H, Num, N) ->
MaxLength = maps:get(max_header_value_length, Opts, 4096),
case match_eol(Buffer, 0) of
nomatch when byte_size(Buffer) > MaxLength ->
- error_terminate(431, State#state{in_state=PS#ps_header{headers=H}},
+ error_terminate(431, State#state{in_state=PS#ps_header{headers=H, num_headers=Num}},
{connection_error, limit_reached,
'A header value is larger than configuration allows. (RFC7230 3.2.5, RFC6585 5)'});
nomatch ->
- {more, State#state{buffer=Buffer, in_state=PS#ps_header{headers=H, name=N}}};
+ {more, State#state{buffer=Buffer, in_state=PS#ps_header{headers=H, num_headers=Num, name=N}}};
_ ->
- parse_hd_value(Buffer, State, H, N, <<>>)
+ parse_hd_value(Buffer, State, H, Num, N, <<>>)
end.

-parse_hd_value(<< $\r, $\n, Rest/bits >>, S, Headers0, Name, SoFar) ->
+parse_hd_value(<< $\r, $\n, Rest/bits >>, S, Headers0, Num, Name, SoFar) ->
Value = clean_value_ws_end(SoFar, byte_size(SoFar) - 1),
Headers = case maps:get(Name, Headers0, undefined) of
undefined -> Headers0#{Name => Value};
@@ -692,9 +705,13 @@ parse_hd_value(<< $\r, $\n, Rest/bits >>, S, Headers0, Name, SoFar) ->
Value0 when Name =:= <<"cookie">> -> Headers0#{Name => << Value0/binary, "; ", Value/binary >>};
Value0 -> Headers0#{Name => << Value0/binary, ", ", Value/binary >>}
end,
- parse_header(Rest, S, Headers);
-parse_hd_value(<< C, Rest/bits >>, S, H, N, SoFar) ->
- parse_hd_value(Rest, S, H, N, << SoFar/binary, C >>).
+ parse_header(Rest, S, Headers, Num + 1);
+parse_hd_value(<< $\0, _/bits >>, S=#state{in_state=PS}, H, Num, _, _) ->
+ error_terminate(400, S#state{in_state=PS#ps_header{headers=H, num_headers=Num}},
+ {connection_error, protocol_error,
+ 'NUL byte is not allowed in header value. (RFC9110 5.5)'});
+parse_hd_value(<< C, Rest/bits >>, S, H, Num, N, SoFar) ->
+ parse_hd_value(Rest, S, H, Num, N, << SoFar/binary, C >>).

clean_value_ws_end(_, -1) ->
<<>>;
--
2.45.4

7 changes: 6 additions & 1 deletion SPECS/rabbitmq-server/rabbitmq-server.spec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Summary: rabbitmq-server
Name: rabbitmq-server
Version: 3.13.7
Release: 7%{?dist}
Release: 8%{?dist}
License: Apache-2.0 and MPL 2.0
Vendor: Microsoft Corporation
Distribution: Azure Linux
Expand All @@ -17,6 +17,8 @@ Patch4: CVE-2026-7790.patch
Patch5: CVE-2026-43973.patch
Patch6: CVE-2026-43966.patch
Patch7: CVE-2026-44839.patch
Patch8: CVE-2026-59248.patch
Patch9: CVE-2026-65624.patch

BuildRequires: elixir
BuildRequires: erlang
Expand Down Expand Up @@ -73,6 +75,9 @@ done
%{_libdir}/rabbitmq/lib/rabbitmq_server-%{version}/*

%changelog
* Fri Jul 31 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 3.13.7-8
- Patch for CVE-2026-65624, CVE-2026-59248

* Mon Jul 06 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 3.13.7-7
- Patch for CVE-2026-43966, CVE-2026-44839

Expand Down
Loading