44import threading
55import tempfile
66from pathlib import Path
7+ from urllib .parse import quote
78
89from playwright .sync_api import sync_playwright
910
1011ROOT = Path (__file__ ).resolve ().parents [1 ]
1112
1213
14+ def check_search_safety (page , base ):
15+ """Exercise URL queries through the real search worker and suggestion DOM."""
16+ for query in (
17+ 'pyth' ,
18+ '-<b>probe</b> pyth' ,
19+ '-<img/src=x/onerror=window.__searchProbe=1> pyth' ,
20+ '-<b>probe</b> pyth' ,
21+ ):
22+ print ('Checking suggestion:' , query , flush = True )
23+ page .goto (base + '?q=' + quote (query , safe = '' ))
24+ search = page .get_by_role ('textbox' , name = 'Search' )
25+ page .wait_for_function ('!document.querySelector(".md-search__input").disabled' )
26+ search .focus ()
27+ search .press ('End' )
28+ search .press ('Backspace' )
29+ search .press ('h' )
30+ # A nonempty suggestion proves the vulnerable renderer was reached.
31+ page .wait_for_function ('document.querySelector("[data-md-component=search-suggest]").textContent.length > 0' , timeout = 30000 )
32+ suggestion = page .locator ('[data-md-component="search-suggest"]' )
33+ text = suggestion .text_content ()
34+ assert text .startswith (query [:- 4 ]), (query , text )
35+ assert suggestion .locator ('*' ).count () == 0 , query
36+ assert page .evaluate ('window.__searchProbe' ) is None , query
37+ if query == 'pyth' :
38+ assert text .startswith ('python' ), text
39+ search .press ('ArrowRight' )
40+ assert search .input_value () == text
41+ print ('PASS: search suggestions render URL input as text, including markup and encoded entities; normal completion works.' )
42+
43+
1344class Handler (http .server .SimpleHTTPRequestHandler ):
1445 def do_GET (self ):
1546 if self .path .startswith ('/python_foundation/' ):
@@ -32,6 +63,7 @@ def check():
3263 page .set_default_timeout (10000 )
3364 errors = []
3465 page .on ('pageerror' , lambda error : errors .append (str (error )))
66+ check_search_safety (page , base )
3567 page .goto (base )
3668 assert page .title () == 'Introduction to Python: A Guided Beginner Course'
3769 assert page .locator ('.course-chip' ).inner_text () == 'Introduction to Python: A Guided Beginner Course'
0 commit comments