Skip to content

Commit

Permalink
Require word boundaries before search query filters (CVE-2024-39317)
Browse files Browse the repository at this point in the history
Requiring a word boundary before the start of a filter prevents backtracking, as substrings of the filter name are no longer valid filter names.

This also makes matching around an order of magnitude faster.
  • Loading branch information
RealOrangeOne authored and gasman committed Jul 11, 2024
1 parent d398c3f commit 31b1e85
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 12 deletions.
24 changes: 24 additions & 0 deletions wagtail/search/tests/test_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,30 @@ def test_phrase_with_filter(self):
self.assertDictEqual(filters.dict(), {"author": "foo bar", "bar": "beer"})
self.assertEqual(repr(query), repr(Phrase("hello world")))

def test_long_queries(self):
filters, query = parse_query_string("0" * 60_000)
self.assertEqual(filters.dict(), {})
self.assertEqual(repr(query), repr(PlainText("0" * 60_000)))

filters, _ = parse_query_string(f'{"a" * 60_000}:"foo bar"')
self.assertEqual(filters.dict(), {"a" * 60_000: "foo bar"})

def test_long_filter_value(self):
filters, _ = parse_query_string(f'foo:ba{"r" * 60_000}')
self.assertEqual(filters.dict(), {"foo": f"ba{"r" * 60_000}"})

def test_joined_filters(self):
filters, query = parse_query_string("foo:bar:baz")
self.assertEqual(filters.dict(), {"foo": "bar"})
self.assertEqual(repr(query), repr(PlainText(":baz")))

filters, query = parse_query_string("foo:'bar':baz")
self.assertEqual(filters.dict(), {"foo": "bar"})
self.assertEqual(repr(query), repr(PlainText(":baz")))

filters, query = parse_query_string("foo:'bar:baz'")
self.assertEqual(filters.dict(), {"foo": "bar:baz"})

def test_multiple_phrases(self):
filters, query = parse_query_string('"hello world" "hi earth"')

Expand Down
18 changes: 6 additions & 12 deletions wagtail/search/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ def balanced_reduce(operator, seq, initializer=NOT_SET):

MAX_QUERY_STRING_LENGTH = 255

filters_regexp = re.compile(r'\b(\w+):(\w+|"[^"]+"|\'[^\']+\')')


def normalise_query_string(query_string):
# Truncate query string
Expand All @@ -83,20 +85,12 @@ def normalise_query_string(query_string):


def separate_filters_from_query(query_string):
filters_regexp = r'(\w+):(\w+|"[^"]+"|\'[^\']+\')'

filters = QueryDict(mutable=True)
for match_object in re.finditer(filters_regexp, query_string):
for match_object in filters_regexp.finditer(query_string):
key, value = match_object.groups()
filters.update(
{
key: value.strip('"')
if value.strip('"') is not value
else value.strip("'")
}
)

query_string = re.sub(filters_regexp, "", query_string).strip()
filters.update({key: value.strip("\"'")})

query_string = filters_regexp.sub("", query_string).strip()

return filters, query_string

Expand Down

0 comments on commit 31b1e85

Please sign in to comment.