Skip to content

Commit a306964

Browse files
committed
Enforce longpoll batch size
This is additional hardening against GHSA-628h-q48j-jr6q. It enforces a maximum of 100 entries per longpoll request. The client already limits this since 1.8.6. For anyone updating, where many longpoll events are expected on a single request (very unlikely), update to 1.8.6 or 1.8.7 first.
1 parent 0ac805e commit a306964

2 files changed

Lines changed: 32 additions & 3 deletions

File tree

lib/phoenix/transports/long_poll.ex

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ defmodule Phoenix.Transports.LongPoll do
55
# The maximum is 10MB but read_body will cap the whole request at ~8MB,
66
# so this acts as a secondary protection mechanism.
77
@max_base64_size 10_000_000
8-
# TODO: enforce batch size on the server in the next release
9-
# @max_poll_batch_size 100
8+
@max_poll_batch_size 100
109
@connect_info_opts [:check_csrf]
1110

1211
import Plug.Conn
@@ -87,7 +86,7 @@ defmodule Phoenix.Transports.LongPoll do
8786
["application/x-ndjson"] ->
8887
body
8988
|> String.splitter(["\n", "\r\n"])
90-
# |> Stream.take(@max_poll_batch_size)
89+
|> Stream.take(@max_poll_batch_size)
9190
|> Enum.find_value(fn part ->
9291
msg =
9392
case part do

test/phoenix/integration/long_poll_channels_test.exs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,36 @@ defmodule Phoenix.Integration.LongPollChannelsTest do
642642
assert resp.status == 200
643643
assert resp.body["status"] == 408
644644
end
645+
646+
test "ignores ndjson batch entries after the first 100", %{topic: topic} do
647+
vsn = "2.0.0"
648+
join_ref = "1"
649+
session = join("/ws", topic, vsn, join_ref)
650+
Phoenix.PubSub.subscribe(__MODULE__, topic)
651+
652+
messages =
653+
for n <- 1..101 do
654+
%{
655+
"topic" => topic,
656+
"event" => "new_msg",
657+
"ref" => to_string(n + 1),
658+
"join_ref" => join_ref,
659+
"payload" => %{"body" => "msg#{n}"}
660+
}
661+
end
662+
663+
resp = poll(:post, "/ws", vsn, session, messages)
664+
assert resp.body["status"] == 200
665+
666+
new_msg_bodies =
667+
for _ <- 1..100 do
668+
assert_receive %Broadcast{event: "new_msg", payload: %{"body" => body}}
669+
body
670+
end
671+
672+
assert new_msg_bodies == for(n <- 1..100, do: "msg#{n}")
673+
refute_receive %Broadcast{event: "new_msg", payload: %{"body" => "msg101"}}
674+
end
645675
end
646676

647677
for {serializer, vsn, join_ref} <- [

0 commit comments

Comments
 (0)