types: reject port-bearing server_url under base_domain

This commit is contained in:
Kristoffer Dalby
2026-06-16 14:03:39 +00:00
parent e4cd846075
commit abfd5c9236
2 changed files with 44 additions and 15 deletions
+3 -15
View File
@@ -1301,23 +1301,11 @@ func isSafeServerURL(serverURL, baseDomain string) error {
return errServerURLSame
}
serverDomainParts := strings.Split(server.Host, ".")
baseDomainParts := strings.Split(baseDomain, ".")
if len(serverDomainParts) <= len(baseDomainParts) {
return nil
if strings.HasSuffix(server.Hostname(), "."+baseDomain) {
return errServerURLSuffix
}
s := len(serverDomainParts)
b := len(baseDomainParts)
for i := range baseDomainParts {
if serverDomainParts[s-i-1] != baseDomainParts[b-i-1] {
return nil
}
}
return errServerURLSuffix
return nil
}
type deprecator struct {
+41
View File
@@ -507,6 +507,47 @@ func TestSafeServerURL(t *testing.T) {
}
}
func TestSafeServerURLWithPort(t *testing.T) {
tests := []struct {
serverURL, baseDomain,
wantErr string
}{
{
serverURL: "https://server.headscale.com:443",
baseDomain: "headscale.com",
wantErr: errServerURLSuffix.Error(),
},
{
serverURL: "https://server.subdomain.headscale.com:8080",
baseDomain: "headscale.com",
wantErr: errServerURLSuffix.Error(),
},
{
serverURL: "https://headscale.com:443",
baseDomain: "headscale.com",
wantErr: errServerURLSame.Error(),
},
{
serverURL: "https://example.com:8080",
baseDomain: "example.org",
},
}
for _, tt := range tests {
testName := fmt.Sprintf("server=%s domain=%s", tt.serverURL, tt.baseDomain)
t.Run(testName, func(t *testing.T) {
err := isSafeServerURL(tt.serverURL, tt.baseDomain)
if tt.wantErr != "" {
assert.EqualError(t, err, tt.wantErr)
return
}
assert.NoError(t, err)
})
}
}
// TestConfigJSONOmitsSecrets verifies that marshalling a [Config] to JSON
// (as /debug/config does via [state.State.DebugConfig]) does not leak the
// Postgres password, the OIDC client secret, or the headscale admin