CVE-2022-42975 (published 2022-10-17T06:15Z)

socket/transport.ex in Phoenix before 1.6.14 mishandles check_origin wildcarding. NOTE: LiveView applications are unaffected by default because of the presence of a LiveView CSRF token.

CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N)

Weakness information:
cwe_id: NVD-CWE-Other
cwe_name: Other
description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/phoenixframework/phoenix
commit_details: repo_url: https://github.com/phoenixframework/phoenix
author: Chris McCord
author_date: 2022-10-07 14:19:23-04:00
msg: Fix wildcard check_origin vulnerability.

Previously, our documentation points to a wilcard example of:

    check_origin: [
      "//*.other.com"
    ]

Which should allow any subdomain of "other.com", but our comparison
for `"//*.other.com"` would allow `api.any-other.com`, which would
allow an attacker to register a domain with a custom prefix of a target
domain and pass origin checks. This patch ensures the `String.ends_with?`
check includes the subdomain dot prefix.

Who is affected?

Only those using a wildcard check origin are affected, and potential
exploits are limited to allowing unauthenticated channel connections
from a bad host. Because LiveView adds its own csrf token to the
connection by default, LiveView applications with wildcard check origin
would refuse connection under this scenario. Additionally, channel
applications utilizing token based authentication would require the
attacker to also have a valid token to connection from a bad host.
Phoenix channels does not allow access to cookies, so an attacker would
also not be able to pass their own cookies from a bad host.
repository: repo_url: https://github.com/phoenixframework/phoenix
repo_name: phoenixframework/phoenix
description: Peace of mind from prototype to production
repo_language: Elixir
owner: phoenixframework
file_changes: filename: transport.ex
change_type: ModificationType.MODIFY
diff: @@ -624,7 +624,7 @@ defmodule Phoenix.Socket.Transport do
   defp compare_host?(_request_host, nil),
     do: true
   defp compare_host?(request_host, "*." <> allowed_host),
-    do: String.ends_with?(request_host, allowed_host)
+    do: request_host == allowed_host or String.ends_with?(request_host, "." <> allowed_host)
   defp compare_host?(request_host, allowed_host),
     do: request_host == allowed_host
 

programming_language: Ruby
filename: transport_test.exs
change_type: ModificationType.MODIFY
diff: @@ -85,6 +85,12 @@ defmodule Phoenix.Socket.TransportTest do
       refute conn.halted
       conn = check_origin("https://org1.ex.com", check_origin: origins)
       refute conn.halted
+
+      conn = check_origin("https://ex.com", check_origin: origins)
+      refute conn.halted
+
+      conn = check_origin("https://org1.prefix-ex.com", check_origin: origins)
+      assert conn.halted
     end
 
     test "nested wildcard subdomains" do
@@ -93,6 +99,15 @@ defmodule Phoenix.Socket.TransportTest do
       conn = check_origin("http://org1.foo.example.com", check_origin: origins)
       refute conn.halted
 
+      conn = check_origin("http://foo.example.com", check_origin: origins)
+      refute conn.halted
+
+      conn = check_origin("http://bad.example.com", check_origin: origins)
+      assert conn.halted
+
+      conn = check_origin("http://org1.prefix-foo.example.com", check_origin: origins)
+      assert conn.halted
+
       conn = check_origin("http://org1.bar.example.com", check_origin: origins)
       assert conn.halted
       assert conn.status == 403

programming_language: Ruby