fix(mail): prevent ReDoS in Search by escaping user input

Use regexp.QuoteMeta to treat Query and FromFilter as literal strings
instead of raw regex patterns. This prevents ReDoS attacks from malicious
patterns and provides more intuitive literal string matching for users.

Fixes gt-kwa09

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gastown/crew/joe
2026-01-04 23:53:19 -08:00
committed by Steve Yegge
parent 254288800d
commit 2c6654b5b2

View File

@@ -640,16 +640,18 @@ type SearchOptions struct {
// Search finds messages matching the given criteria. // Search finds messages matching the given criteria.
// Returns messages from both inbox and archive. // Returns messages from both inbox and archive.
// Query and FromFilter are treated as literal strings (not regex) to prevent ReDoS.
func (m *Mailbox) Search(opts SearchOptions) ([]*Message, error) { func (m *Mailbox) Search(opts SearchOptions) ([]*Message, error) {
// Compile regex // Use QuoteMeta to escape special regex chars - prevents ReDoS attacks
re, err := regexp.Compile("(?i)" + opts.Query) // Case-insensitive // and provides intuitive literal string matching for users
re, err := regexp.Compile("(?i)" + regexp.QuoteMeta(opts.Query))
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid search pattern: %w", err) return nil, fmt.Errorf("invalid search pattern: %w", err)
} }
var fromRe *regexp.Regexp var fromRe *regexp.Regexp
if opts.FromFilter != "" { if opts.FromFilter != "" {
fromRe, err = regexp.Compile("(?i)" + opts.FromFilter) fromRe, err = regexp.Compile("(?i)" + regexp.QuoteMeta(opts.FromFilter))
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid from pattern: %w", err) return nil, fmt.Errorf("invalid from pattern: %w", err)
} }