Fix basePath validation for dashboard template

This commit is contained in:
Gina A.
2026-02-25 17:12:15 +01:00
committed by GitHub
parent 0d60499f13
commit a0654afa97
3 changed files with 93 additions and 4 deletions
+1 -1
View File
@@ -2,11 +2,11 @@ package dashboard
import (
"fmt"
"html/template"
"io/fs"
"net/http"
"net/url"
"strings"
"text/template"
"github.com/gorilla/mux"
"github.com/rs/zerolog/log"
+6 -3
View File
@@ -3,7 +3,7 @@ package static
import (
"errors"
"fmt"
"path"
"regexp"
"strings"
"time"
@@ -57,6 +57,9 @@ const (
DefaultUDPTimeout = 3 * time.Second
)
// Allowed characters in URL following RFC 3986 (https://www.rfc-editor.org/rfc/rfc3986#section-2)
var validBasePath = regexp.MustCompile(`^/[a-zA-Z0-9/_.-]*$`)
// Configuration is the static configuration.
type Configuration struct {
Global *Global `description:"Global configuration options" json:"global,omitempty" toml:"global,omitempty" yaml:"global,omitempty" export:"true"`
@@ -464,8 +467,8 @@ func (c *Configuration) ValidateConfiguration() error {
}
}
if c.API != nil && !path.IsAbs(c.API.BasePath) {
return errors.New("API basePath must be a valid absolute path")
if c.API != nil && !validBasePath.MatchString(c.API.BasePath) {
return errors.New("API basePath must be a valid absolute URL path")
}
if c.OCSP != nil {
+86
View File
@@ -282,3 +282,89 @@ func TestConfiguration_SetEffectiveConfiguration(t *testing.T) {
})
}
}
func TestValidateConfiguration_BasePath(t *testing.T) {
tests := []struct {
desc string
basePath string
expectErr bool
}{
{
desc: "valid simple path",
basePath: "/api",
expectErr: false,
},
{
desc: "valid path with segments",
basePath: "/my/base/path",
expectErr: false,
},
{
desc: "valid path with allowed special chars",
basePath: "/valid/path-123",
expectErr: false,
},
{
desc: "relative path",
basePath: "api/path",
expectErr: true,
},
{
desc: "XSS payload",
basePath: `/api/"></script><script>alert("XSS")</script>`,
expectErr: true,
},
{
desc: "path with spaces",
basePath: "/path with spaces",
expectErr: true,
},
{
desc: "path with angle brackets",
basePath: "/path/<evil>",
expectErr: true,
},
{
desc: "path with query string",
basePath: "/api?foo=bar",
expectErr: true,
},
{
desc: "path with fragment",
basePath: "/api#section",
expectErr: true,
},
{
desc: "valid root path",
basePath: "/",
expectErr: false,
},
{
desc: "path with quote",
basePath: "/api/'onclick=alert(1)",
expectErr: true,
},
{
desc: "path with encoded character",
basePath: "/api%2Ftoto",
expectErr: true,
},
}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
cfg := &Configuration{
API: &API{BasePath: test.basePath},
}
err := cfg.ValidateConfiguration()
if test.expectErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}