From c3026c34b042cc044cddfc5674d5f5ad69bb845d Mon Sep 17 00:00:00 2001 From: grm Date: Fri, 18 Sep 2026 13:50:35 +0300 Subject: Security: Throttle search, cap its words and give the query a deadline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /search runs an unindexed regular-expression scan over every published post, built from up to fifty ".*"-joined words, for anyone who asks — the cheapest way for a bot to keep Postgres busy. Queries are now cut at eight words (more never improve the answer), each address gets thirty searches and then thirty a minute, and the statement is cancelled after five seconds; a timeout reads as no results and is logged, rather than a 500. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A --- internal/web/search_test.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'internal/web/search_test.go') diff --git a/internal/web/search_test.go b/internal/web/search_test.go index 6ced39b..7ade83f 100644 --- a/internal/web/search_test.go +++ b/internal/web/search_test.go @@ -10,11 +10,12 @@ import ( func TestSearchPattern(t *testing.T) { for q, want := range map[string]string{ - "go tem": "go.*tem", - " a.b (c) ": `a\.b.*\(c\)`, - "one": "one", - " ": "", - "": "", + "go tem": "go.*tem", + " a.b (c) ": `a\.b.*\(c\)`, + "one": "one", + " ": "", + "": "", + "a b c d e f g h i j": "a.*b.*c.*d.*e.*f.*g.*h", // maxSearchWords } { if got := searchPattern(q); got != want { t.Errorf("searchPattern(%q) = %q, want %q", q, got, want) -- cgit v1.2.3