From 9a2a2cc744866d0729db9abd1aae6d3d5c8c9b9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Valim?= <jose.valim@gmail.com>
Date: Wed, 28 Oct 2026 11:44:55 +0100
Subject: [PATCH] Bind port limits during URI.parse (CVE-2026-109821)

---
 lib/elixir/lib/uri.ex               | 21 +++++++++++++++++++--
 lib/elixir/test/elixir/uri_test.exs |  8 ++++++++
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/lib/elixir/lib/uri.ex b/lib/elixir/lib/uri.ex
index 3c6433c05..d25a9c995 100644
--- a/lib/elixir/lib/uri.ex
+++ b/lib/elixir/lib/uri.ex
@@ -813,7 +813,24 @@ def parse(string) when is_binary(string) do
     {authority, userinfo, host, port} = split_authority(authority_with_slashes)
 
     scheme = scheme && String.downcase(scheme)
-    port = port || (scheme && default_port(scheme))
+
+    # Leading zeros are removed and then ports with more than
+    # 6 digits or outside of the valid range are discarded
+    port =
+      case port && String.trim_leading(port, "0") do
+        nil ->
+          scheme && default_port(scheme)
+
+        "" ->
+          0
+
+        port when byte_size(port) <= 6 ->
+          port = String.to_integer(port)
+          if port in 0..65535, do: port
+
+        _ ->
+          nil
+      end
 
     %URI{
       scheme: scheme,
@@ -849,7 +866,7 @@ defp split_authority("//" <> authority) do
     destructure [_, _, userinfo, host, _, port], components
     userinfo = nilify(userinfo)
     host = if nilify(host), do: host |> String.trim_leading("[") |> String.trim_trailing("]")
-    port = if nilify(port), do: String.to_integer(port)
+    port = nilify(port)
 
     {authority, userinfo, host, port}
   end
diff --git a/lib/elixir/test/elixir/uri_test.exs b/lib/elixir/test/elixir/uri_test.exs
index 8772ec97d..7b5bf59ce 100644
--- a/lib/elixir/test/elixir/uri_test.exs
+++ b/lib/elixir/test/elixir/uri_test.exs
@@ -781,6 +781,14 @@ test "splits authority" do
       }
 
       assert URI.parse("http://foo.com:4444") == expected_uri
+
+      assert URI.parse("http://foo.com:65535").port == 65535
+      assert URI.parse("http://foo.com:065535").port == 65535
+      assert URI.parse("http://foo.com:65536").port == nil
+      assert URI.parse("http://foo.com:0000000065535").port == 65535
+      assert URI.parse("http://foo.com:0000000065536").port == nil
+      assert URI.parse("http://foo.com:0000000000").port == 0
+      assert URI.parse("http://foo.com:#{String.duplicate("9", 1000)}").port == nil
     end
 
     test "can parse bad URIs" do
-- 
2.52.0

