@@ -287,3 +287,149 @@ def test_is_root_domain_helper(self):
287
287
# Invalid domains - should return False
288
288
assert watchdog ._is_root_domain ('example' ) is False
289
289
assert watchdog ._is_root_domain ('' ) is False
290
+
291
+
292
+ class TestUrlProhibitlistSecurity :
293
+ """Tests for URL prohibitlist (blocked domains) behavior and matching semantics."""
294
+
295
+ def test_simple_prohibited_domains (self ):
296
+ """Domain-only patterns block exact host and www, but not other subdomains."""
297
+ from bubus import EventBus
298
+
299
+ from browser_use .browser .watchdogs .security_watchdog import SecurityWatchdog
300
+
301
+ browser_profile = BrowserProfile (prohibited_domains = ['example.com' , 'test.org' ], headless = True , user_data_dir = None )
302
+ browser_session = BrowserSession (browser_profile = browser_profile )
303
+ event_bus = EventBus ()
304
+ watchdog = SecurityWatchdog (browser_session = browser_session , event_bus = event_bus )
305
+
306
+ # Block exact and www
307
+ assert watchdog ._is_url_allowed ('https://example.com' ) is False
308
+ assert watchdog ._is_url_allowed ('https://www.example.com' ) is False
309
+ assert watchdog ._is_url_allowed ('https://test.org' ) is False
310
+ assert watchdog ._is_url_allowed ('https://www.test.org' ) is False
311
+
312
+ # Allow other subdomains when only root is prohibited
313
+ assert watchdog ._is_url_allowed ('https://mail.example.com' ) is True
314
+ assert watchdog ._is_url_allowed ('https://api.test.org' ) is True
315
+
316
+ # Allow unrelated domains
317
+ assert watchdog ._is_url_allowed ('https://notexample.com' ) is True
318
+
319
+ def test_glob_pattern_prohibited (self ):
320
+ """Wildcard patterns block subdomains and main domain for http/https only."""
321
+ from bubus import EventBus
322
+
323
+ from browser_use .browser .watchdogs .security_watchdog import SecurityWatchdog
324
+
325
+ browser_profile = BrowserProfile (prohibited_domains = ['*.example.com' ], headless = True , user_data_dir = None )
326
+ browser_session = BrowserSession (browser_profile = browser_profile )
327
+ event_bus = EventBus ()
328
+ watchdog = SecurityWatchdog (browser_session = browser_session , event_bus = event_bus )
329
+
330
+ # Block subdomains and main domain
331
+ assert watchdog ._is_url_allowed ('https://example.com' ) is False
332
+ assert watchdog ._is_url_allowed ('https://www.example.com' ) is False
333
+ assert watchdog ._is_url_allowed ('https://mail.example.com' ) is False
334
+
335
+ # Allow other domains
336
+ assert watchdog ._is_url_allowed ('https://notexample.com' ) is True
337
+
338
+ # Wildcard with domain-only should not apply to non-http(s)
339
+ assert watchdog ._is_url_allowed ('chrome://abc.example.com' ) is True
340
+
341
+ def test_full_url_prohibited_patterns (self ):
342
+ """Full URL patterns block only matching scheme/host/prefix."""
343
+ from bubus import EventBus
344
+
345
+ from browser_use .browser .watchdogs .security_watchdog import SecurityWatchdog
346
+
347
+ browser_profile = BrowserProfile (prohibited_domains = ['https://wiki.org' , 'brave://*' ], headless = True , user_data_dir = None )
348
+ browser_session = BrowserSession (browser_profile = browser_profile )
349
+ event_bus = EventBus ()
350
+ watchdog = SecurityWatchdog (browser_session = browser_session , event_bus = event_bus )
351
+
352
+ # Scheme-specific blocking
353
+ assert watchdog ._is_url_allowed ('http://wiki.org' ) is True
354
+ assert watchdog ._is_url_allowed ('https://wiki.org' ) is False
355
+ assert watchdog ._is_url_allowed ('https://wiki.org/path' ) is False
356
+
357
+ # Internal URL prefix blocking
358
+ assert watchdog ._is_url_allowed ('brave://anything/' ) is False
359
+ assert watchdog ._is_url_allowed ('chrome://settings' ) is True
360
+
361
+ def test_internal_urls_allowed_even_when_prohibited (self ):
362
+ """Internal new-tab/blank URLs are always allowed regardless of prohibited list."""
363
+ from bubus import EventBus
364
+
365
+ from browser_use .browser .watchdogs .security_watchdog import SecurityWatchdog
366
+
367
+ browser_profile = BrowserProfile (prohibited_domains = ['*' ], headless = True , user_data_dir = None )
368
+ browser_session = BrowserSession (browser_profile = browser_profile )
369
+ event_bus = EventBus ()
370
+ watchdog = SecurityWatchdog (browser_session = browser_session , event_bus = event_bus )
371
+
372
+ assert watchdog ._is_url_allowed ('about:blank' ) is True
373
+ assert watchdog ._is_url_allowed ('chrome://new-tab-page/' ) is True
374
+ assert watchdog ._is_url_allowed ('chrome://new-tab-page' ) is True
375
+ assert watchdog ._is_url_allowed ('chrome://newtab/' ) is True
376
+
377
+ def test_prohibited_ignored_when_allowlist_present (self ):
378
+ """When allowlist is set, prohibited list is ignored by design."""
379
+ from bubus import EventBus
380
+
381
+ from browser_use .browser .watchdogs .security_watchdog import SecurityWatchdog
382
+
383
+ browser_profile = BrowserProfile (
384
+ allowed_domains = ['*.example.com' ],
385
+ prohibited_domains = ['https://example.com' ],
386
+ headless = True ,
387
+ user_data_dir = None ,
388
+ )
389
+ browser_session = BrowserSession (browser_profile = browser_profile )
390
+ event_bus = EventBus ()
391
+ watchdog = SecurityWatchdog (browser_session = browser_session , event_bus = event_bus )
392
+
393
+ # Allowed by allowlist even though exact URL is in prohibited list
394
+ assert watchdog ._is_url_allowed ('https://example.com' ) is True
395
+ assert watchdog ._is_url_allowed ('https://www.example.com' ) is True
396
+
397
+ # Not in allowlist => blocked (prohibited list is not consulted in this mode)
398
+ assert watchdog ._is_url_allowed ('https://api.example.com' ) is True # wildcard allowlist includes this
399
+ # A domain outside the allowlist should be blocked
400
+ assert watchdog ._is_url_allowed ('https://notexample.com' ) is False
401
+
402
+ def test_auth_credentials_do_not_cause_false_block (self ):
403
+ """Credentials injection with prohibited domain in username should not block unrelated hosts."""
404
+ from bubus import EventBus
405
+
406
+ from browser_use .browser .watchdogs .security_watchdog import SecurityWatchdog
407
+
408
+ browser_profile = BrowserProfile (prohibited_domains = ['example.com' ], headless = True , user_data_dir = None )
409
+ browser_session = BrowserSession (browser_profile = browser_profile )
410
+ event_bus = EventBus ()
411
+ watchdog = SecurityWatchdog (browser_session = browser_session , event_bus = event_bus )
412
+
413
+ # Host is malicious.com, should not be blocked just because username contains example.com
414
+ assert watchdog .
_is_url_allowed (
'https://example.com:[email protected] ' )
is True
415
+ assert watchdog .
_is_url_allowed (
'https://[email protected] ' )
is True
416
+ assert watchdog .
_is_url_allowed (
'https://example.com%[email protected] ' )
is True
417
+ assert watchdog .
_is_url_allowed (
'https://example.com%[email protected] ' )
is True
418
+
419
+ # Legitimate credentials to a prohibited host should be blocked
420
+ assert watchdog .
_is_url_allowed (
'https://user:[email protected] ' )
is False
421
+
422
+ def test_case_insensitive_prohibited_domains (self ):
423
+ """Prohibited domain matching should be case-insensitive."""
424
+ from bubus import EventBus
425
+
426
+ from browser_use .browser .watchdogs .security_watchdog import SecurityWatchdog
427
+
428
+ browser_profile = BrowserProfile (prohibited_domains = ['Example.COM' ], headless = True , user_data_dir = None )
429
+ browser_session = BrowserSession (browser_profile = browser_profile )
430
+ event_bus = EventBus ()
431
+ watchdog = SecurityWatchdog (browser_session = browser_session , event_bus = event_bus )
432
+
433
+ assert watchdog ._is_url_allowed ('https://example.com' ) is False
434
+ assert watchdog ._is_url_allowed ('https://WWW.EXAMPLE.COM' ) is False
435
+ assert watchdog ._is_url_allowed ('https://mail.example.com' ) is True
0 commit comments