diff options
Diffstat (limited to 'internal/web/render.go')
| -rw-r--r-- | internal/web/render.go | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/internal/web/render.go b/internal/web/render.go index cf72d41..67c7a37 100644 --- a/internal/web/render.go +++ b/internal/web/render.go @@ -130,14 +130,21 @@ func Themes() []string { return names } +// themeNameRe is the allowlist a theme name must match: letters, digits, +// underscore, hyphen only. Legitimate theme stems (built-in or user) already +// fit this shape; it is deliberately stricter than "no path separators" so +// it rejects "." / ".." / any other filesystem metacharacter outright +// instead of trying to enumerate what's unsafe. +var themeNameRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`) + // themeCSS returns one theme's CSS: the user file // ${XDG_CONFIG_HOME:-~/.config}/lectio/themes/<name>.css if it exists, // otherwise the embedded static/themes/<name>.css, otherwise an error. -// name must be a bare file stem (no path separators or "..") -- callers -// (B2's /theme.css?name= handler) pass this straight through from an HTTP -// query parameter, so this rejects path traversal rather than trusting it. +// name must match themeNameRe -- callers (B2's /theme.css?name= handler) +// pass this straight through from an HTTP query parameter, so this rejects +// path traversal rather than trusting it. func themeCSS(name string) ([]byte, error) { - if name == "" || name != filepath.Base(name) || strings.ContainsAny(name, `/\`) { + if !themeNameRe.MatchString(name) { return nil, fmt.Errorf("web: invalid theme name %q", name) } |
