@marcel91200 / caddy Mirror · read-only / commits / af29f9ea
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 06:00 UTC

admin: fix origin allow-list host comparison to be case-insensitive (#7973)

The admin origin allow-list compared origin.Host against the allowed URL's Host with byte-for-byte equality. url.Parse does not normalize host case, so an allowed 'http://Example.com:8080' rejected a client origin of 'http://example.com:8080' even though RFC 3986 §3.2.2 says host names are case-insensitive. Use strings.EqualFold. Signed-off-by: Mohammed Al Sahaf <msaa1990@gmail.com>

Mohammed Al Sahaf committed Sep 3, 2026 at 00:46 UTC af29f9ea919603408faf33c0f45af53d61db89a5
2 files changed +62 -1
admin.go
+3 -1
@@ -994,7 +994,9 @@ func (h adminHandler) originAllowed(origin *url.URL) bool {
994 if allowedOrigin.Scheme != "" && origin.Scheme != allowedOrigin.Scheme {
995 continue
996 }
997 - if origin.Host == allowedOrigin.Host {
997 + // Host comparison is case-insensitive per RFC 3986 §3.2.2; url.Parse
998 + // does not normalize host case, so fold it here.
999 + if strings.EqualFold(origin.Host, allowedOrigin.Host) {
1000 return true
1001 }
1002 }
admin_origin_case_test.go new
+59
@@ -0,0 +1,59 @@
1 +// Copyright 2015 Matthew Holt and The Caddy Authors
2 +//
3 +// Licensed under the Apache License, Version 2.0 (the "License");
4 +// you may not use this file except in compliance with the License.
5 +// You may obtain a copy of the License at
6 +//
7 +// http://www.apache.org/licenses/LICENSE-2.0
8 +//
9 +// Unless required by applicable law or agreed to in writing, software
10 +// distributed under the License is distributed on an "AS IS" BASIS,
11 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 +// See the License for the specific language governing permissions and
13 +// limitations under the License.
14 +
15 +package caddy
16 +
17 +import (
18 + "net/url"
19 + "testing"
20 +)
21 +
22 +// TestAdminHandlerOriginAllowed_CaseInsensitiveHost is the regression
23 +// test for the host allow-list comparison being case-sensitive. Per
24 +// RFC 3986 §3.2.2, host names are case-insensitive.
25 +func TestAdminHandlerOriginAllowed_CaseInsensitiveHost(t *testing.T) {
26 + mustParse := func(raw string) *url.URL {
27 + u, err := url.Parse(raw)
28 + if err != nil {
29 + t.Fatalf("invalid URL %q: %v", raw, err)
30 + }
31 + return u
32 + }
33 +
34 + cases := []struct {
35 + name string
36 + allowed *url.URL
37 + origin *url.URL
38 + }{
39 + {
40 + name: "allow-list uppercase, origin lowercase",
41 + allowed: mustParse("http://Example.com:8080"),
42 + origin: mustParse("http://example.com:8080"),
43 + },
44 + {
45 + name: "allow-list lowercase, origin uppercase",
46 + allowed: mustParse("http://example.com:8080"),
47 + origin: mustParse("http://EXAMPLE.com:8080"),
48 + },
49 + }
50 +
51 + for _, tc := range cases {
52 + t.Run(tc.name, func(t *testing.T) {
53 + h := adminHandler{allowedOrigins: []*url.URL{tc.allowed}}
54 + if !h.originAllowed(tc.origin) {
55 + t.Errorf("originAllowed(%v) with allowed %v = false, want true", tc.origin, tc.allowed)
56 + }
57 + })
58 + }
59 +}