From 6259832fb30bdd39e69176fd316ae479574aee61 Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Sun, 4 Oct 2026 19:46:10 +0000 Subject: [PATCH] Allow underscores in allowlist_hosts and referer_blocklist host names The shared entry check refused host names with an underscore, though both lists can match them. The check's comment now says that what it refuses can never match a host name that resolves. Model: opus-5-5 --- README.md | 6 +++--- TODO.md | 18 +++++++++--------- internal/config/config.go | 9 +++++---- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 1f23d26..8597c53 100644 --- a/README.md +++ b/README.md @@ -396,9 +396,9 @@ and the URL is `images.example.com`, and `example.com` An IP address is matched exactly; write an IPv6 address without brackets. An -entry that is neither a host name (letters, digits, hyphens and dots, with at -most one leading dot) nor an IP address, such as one with a port or a `*.` -wildcard, aborts startup. +entry that is neither a host name (letters, digits, hyphens, underscores and +dots, with at most one leading dot) nor an IP address, such as one with a port +or a `*.` wildcard, aborts startup. ### Configuration diff --git a/TODO.md b/TODO.md index 5eb1d53..9307f32 100644 --- a/TODO.md +++ b/TODO.md @@ -34,15 +34,15 @@ P2: security: per-IP rate limiting on the image routes - 2026-10-04 referer blocklist (closes #90): `referer_blocklist` (`PIXA_REFERER_BLOCKLIST`) lists hosts, written and matched as for `allowlist_hosts` with the same matcher; an entry of either list that is - neither a host name (letters, digits, hyphens and dots, with at most one - leading dot) nor an IP address, such as one with a port or a `*.` wildcard, - aborts startup naming the setting and the entry. Both image routes refuse a - request whose `Referer` names a listed host with 403 and a JSON error before - the signature, the cache and the upstream fetch, so it fetches nothing and is - refused whether or not the image is cached. A request with no `Referer`, or - one that does not parse as a URL with a host, is served, so the list is easily - got around; `README.md` and `configs/config.example.yml` say so. It does not - apply to the login and generator pages. + neither a host name (letters, digits, hyphens, underscores and dots, with at + most one leading dot) nor an IP address, such as one with a port or a `*.` + wildcard, aborts startup naming the setting and the entry. Both image routes + refuse a request whose `Referer` names a listed host with 403 and a JSON error + before the signature, the cache and the upstream fetch, so it fetches nothing + and is refused whether or not the image is cached. A request with no + `Referer`, or one that does not parse as a URL with a host, is served, so the + list is easily got around; `README.md` and `configs/config.example.yml` say + so. It does not apply to the login and generator pages. - 2026-10-04 fewer files in the repository root (closes #97): `config.example.yml` moved unchanged to `configs/config.example.yml`, and `README.md`, the comments in `internal/config/config.go` and the startup error diff --git a/internal/config/config.go b/internal/config/config.go index 0a5991e..f4e0fc4 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -742,14 +742,15 @@ func (c *Config) validateConcurrencyLimits() error { return nil } -// hostNamePattern matches a host name: letters, digits, hyphens and dots, -// optionally after one leading dot. -var hostNamePattern = regexp.MustCompile(`^\.?[A-Za-z0-9-][A-Za-z0-9.-]*$`) +// hostNamePattern matches a host name: letters, digits, hyphens, underscores +// and dots, optionally after one leading dot. +var hostNamePattern = regexp.MustCompile(`^\.?[A-Za-z0-9_-][A-Za-z0-9_.-]*$`) // validateHostPattern checks that an entry of the named key, allowlist_hosts // or referer_blocklist, is an IP address or a host name, the host name // optionally with one leading dot for suffix matching. Anything else, such as -// a URL, a port or a "*." wildcard, can never match a host, so it is refused. +// a URL, a port or a "*." wildcard, can never match a host name that resolves, +// so it is refused. // So is "." alone: the allowlist matcher would match it against any host // written with a trailing dot, which in allowlist_hosts disables URL signing. func validateHostPattern(key, host string) error {