From 215ddb7f722841908cf9bc6f54a48b00343b1307 Mon Sep 17 00:00:00 2001 From: user Date: Sun, 15 Mar 2026 11:18:25 -0700 Subject: [PATCH] fix: remove suffix matching from host whitelist Whitelist entries now support exact host matches only. Leading dots in patterns are stripped for backwards compatibility (.example.com becomes an exact match for example.com). Suffix matching that would match arbitrary subdomains is no longer supported. Closes #27 --- internal/imgcache/whitelist.go | 53 +++++++++++++--------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/internal/imgcache/whitelist.go b/internal/imgcache/whitelist.go index df24be2..5baf101 100644 --- a/internal/imgcache/whitelist.go +++ b/internal/imgcache/whitelist.go @@ -6,22 +6,19 @@ import ( ) // HostWhitelist implements the Whitelist interface for checking allowed source hosts. +// Only exact host matches are supported. Leading dots in patterns are stripped +// (e.g. ".example.com" becomes an exact match for "example.com"). type HostWhitelist struct { - // exactHosts contains hosts that must match exactly (e.g., "cdn.example.com") - exactHosts map[string]struct{} - // suffixHosts contains domain suffixes to match (e.g., ".example.com" matches "cdn.example.com") - suffixHosts []string + // hosts contains hosts that must match exactly (e.g., "cdn.example.com") + hosts map[string]struct{} } // NewHostWhitelist creates a whitelist from a list of host patterns. -// Patterns starting with "." are treated as suffix matches. -// Examples: -// - "cdn.example.com" - exact match only -// - ".example.com" - matches cdn.example.com, images.example.com, etc. +// All patterns are treated as exact matches. Leading dots are stripped +// for backwards compatibility (e.g. ".example.com" matches "example.com" only). func NewHostWhitelist(patterns []string) *HostWhitelist { w := &HostWhitelist{ - exactHosts: make(map[string]struct{}), - suffixHosts: make([]string, 0), + hosts: make(map[string]struct{}), } for _, pattern := range patterns { @@ -30,17 +27,22 @@ func NewHostWhitelist(patterns []string) *HostWhitelist { continue } - if strings.HasPrefix(pattern, ".") { - w.suffixHosts = append(w.suffixHosts, pattern) - } else { - w.exactHosts[pattern] = struct{}{} + // Strip leading dot — suffix matching is not supported. + // ".example.com" is treated as exact match for "example.com". + pattern = strings.TrimPrefix(pattern, ".") + + if pattern == "" { + continue } + + w.hosts[pattern] = struct{}{} } return w } // IsWhitelisted checks if a URL's host is in the whitelist. +// Only exact host matches are supported. func (w *HostWhitelist) IsWhitelisted(u *url.URL) bool { if u == nil { return false @@ -51,32 +53,17 @@ func (w *HostWhitelist) IsWhitelisted(u *url.URL) bool { return false } - // Check exact match - if _, ok := w.exactHosts[host]; ok { - return true - } + _, ok := w.hosts[host] - // Check suffix match - for _, suffix := range w.suffixHosts { - if strings.HasSuffix(host, suffix) { - return true - } - // Also match if host equals the suffix without the leading dot - // e.g., pattern ".example.com" should match "example.com" - if host == strings.TrimPrefix(suffix, ".") { - return true - } - } - - return false + return ok } // IsEmpty returns true if the whitelist has no entries. func (w *HostWhitelist) IsEmpty() bool { - return len(w.exactHosts) == 0 && len(w.suffixHosts) == 0 + return len(w.hosts) == 0 } // Count returns the total number of whitelist entries. func (w *HostWhitelist) Count() int { - return len(w.exactHosts) + len(w.suffixHosts) + return len(w.hosts) }