From 0e2c7d1abdf1be71ee00a9fbcc66b02820af31f4 Mon Sep 17 00:00:00 2001 From: admin-mf Date: Thu, 5 Mar 2026 23:56:19 -0600 Subject: [PATCH] security(tools): add response body size limits to search providers Add 2 MB LimitReader to BraveSearch, Tavily, DuckDuckGo, and Perplexity search providers to prevent memory exhaustion from unexpectedly large responses. Matches existing pattern used by GLMSearchProvider. Co-Authored-By: Claude Opus 4.6 --- pkg/tools/web.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/tools/web.go b/pkg/tools/web.go index eeceabd98..fa63bfeb8 100644 --- a/pkg/tools/web.go +++ b/pkg/tools/web.go @@ -22,8 +22,9 @@ const ( perplexityTimeout = 30 * time.Second // Perplexity (LLM-based, slower) fetchTimeout = 60 * time.Second // WebFetchTool - defaultMaxChars = 50000 - maxRedirects = 5 + defaultMaxChars = 50000 + maxRedirects = 5 + searchMaxResponseSize int64 = 2 << 20 // 2 MB — limit for search provider responses ) // Pre-compiled regexes for HTML text extraction @@ -104,7 +105,7 @@ func (p *BraveSearchProvider) Search(ctx context.Context, query string, count in } defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) + body, err := io.ReadAll(io.LimitReader(resp.Body, searchMaxResponseSize)) if err != nil { return "", fmt.Errorf("failed to read response: %w", err) } @@ -191,7 +192,7 @@ func (p *TavilySearchProvider) Search(ctx context.Context, query string, count i } defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) + body, err := io.ReadAll(io.LimitReader(resp.Body, searchMaxResponseSize)) if err != nil { return "", fmt.Errorf("failed to read response: %w", err) } @@ -253,7 +254,7 @@ func (p *DuckDuckGoSearchProvider) Search(ctx context.Context, query string, cou } defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) + body, err := io.ReadAll(io.LimitReader(resp.Body, searchMaxResponseSize)) if err != nil { return "", fmt.Errorf("failed to read response: %w", err) } @@ -367,7 +368,7 @@ func (p *PerplexitySearchProvider) Search(ctx context.Context, query string, cou } defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) + body, err := io.ReadAll(io.LimitReader(resp.Body, searchMaxResponseSize)) if err != nil { return "", fmt.Errorf("failed to read response: %w", err) }