mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-08-29 22:17:14 +00:00
fix(search): cap query length at the shared search-param helper (F3)
whoosh-compat's fieldname tagger is O(n^2) in plain word characters, reachable only through SearchMode.QUERY's whoosh grammar. Measured against the real field registry: ~1s at 10k chars, ~3.7s at 20k, ~14.4s at 40k. The POST selection-filter path (bulk edit, bulk download) has no server-imposed length bound the way the GET path incidentally does via header limits, making an unbounded query a single-request CPU exhaustion vector. Cap both entry points at their shared choke point, _get_tantivy_query_and_mode, with a new QueryTooLongError that reuses the existing SearchQueryError -> 400 routing both callers already have. 4096 chars bounds the worst case to roughly 0.16s by quadratic extrapolation, far beyond any plausible hand-typed query. TEXT and TITLE modes route through simple_search_tokens instead and measure linear even at 20k chars, so the same cap is hygiene for them rather than a fix. Hardcoded rather than a PAPERLESS_* setting: this is a security boundary, and a raisable ceiling could reintroduce the exact hazard it exists to close. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7cb6b32a8f
commit
885bc2fdf3
@@ -34,6 +34,23 @@ class InvalidNumberQuery(SearchQueryError):
|
||||
super().__init__(f"Invalid numeric value {value!r} for field {field!r}.")
|
||||
|
||||
|
||||
class QueryTooLongError(SearchQueryError):
|
||||
"""Raised when a query string exceeds the maximum allowed length.
|
||||
|
||||
whoosh-compat's fieldname tagger is O(n^2) in plain word characters, so an
|
||||
unbounded query is a CPU-exhaustion vector against a single request
|
||||
handler. This is a hard boundary, not a validation nicety.
|
||||
"""
|
||||
|
||||
def __init__(self, length: int, limit: int) -> None:
|
||||
self.length = length
|
||||
self.limit = limit
|
||||
super().__init__(
|
||||
f"The search query is too long ({length} characters). "
|
||||
f"The maximum allowed length is {limit} characters.",
|
||||
)
|
||||
|
||||
|
||||
class MultipleSearchQueryErrors(SearchQueryError):
|
||||
"""Aggregates every user-fixable error from one parse, not just the first."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user